nokia / kong-oidc

OIDC plugin for Kong
Apache License 2.0
457 stars 324 forks source link

How to use the kong-oidc plugin #15

Closed huikang closed 6 years ago

huikang commented 6 years ago

Hi, I am new to Kong. Could anyone provide some step-by-step guidance using this plugin? Thanks.

Trojan295 commented 6 years ago

Right, this repository is missing any docs on how to use it.

In general you'll need an Authorization Server supporting OIDC with a registered client to start. Here you can use either solutions like Keycloak/Gluu or those provided by third party (eg. Google's https://developers.google.com/identity/protocols/OpenIDConnect; in this case, you would use your Google account to login).

After you have the Client ID/secret and OIDC Discovery URL (see. https://auth0.com/docs/tutorials/openid-connect-discovery), you can enable the plugin.

Example curl could look like: curl -XPOST -d 'name=oidc' -d 'config.client_id=<client_id>' -d 'config.client_secret =<client_secret>' -d 'config.discovery=<OIDC_Discovery_url>' http://kong:8001/plugins

After that, before accessing any APIs registered in Kong you will be redirected to the Authorization Server to login there. This will also provide a SSO solution to all the APIs in Kong.

mderazon commented 6 years ago

@Trojan295 thanks.

Can you please clarify a little further ? Does this terminate external opaque session tokens at the Kong gateway and turns them into access tokens / id tokens internally ? If so, how does it work exactly ? Does it do it using Kong own data store ? What about token invalidation ? btw, is Nokia using it in production ?

Would be super helpful to understand this better, any other place we can read about this further ? Thanks 👍

Trojan295 commented 6 years ago

It makes Kong a OIDC Relying Party, so any API behind Kong can profit from the OIDC authentication protection without implementing the OIDC flows.

In practice it uses the Authorization Code grant (https://auth0.com/docs/api-auth/grant/authorization-code). If an unauthenticated user tries to access an API on Kong, on which this plugin is enabled it will redirect the User agent (browser) to the login page on the AS (AS location is set via discovery field in configuration). After successful login the AS gives you an access code and redirects back to Kong. Kong uses the access code to get the access, id and refresh token.

The tokens are stored in an encrypted session cookie. The encryption key is an combination of a few variables (user agent, remote ip address...) and the session_secret, which can be defined, when enabling the plugin (see https://github.com/nokia/kong-oidc/blob/master/kong/plugins/oidc/schema.lua). This field is optional, but highly recommended and has to be random!

If the Kong plugin sees, that there is already a cookie set, it will decrypt it and validate tokens. Refreshing of the access token using the refresh token is handled by this plugin also.

It also adds some information to the request for the upstream server. It sets the X-Userinfo header with the output from the Userinfo Endpoint (https://connect2id.com/products/server/docs/api/userinfo).

In general the OIDC flow and logic is implemented by the lua-resty-openidc package.

mderazon commented 6 years ago

Thanks for the detailed explanation Damian!

The tokens are stored in an encrypted session cookie

So it's stateless and no db is involved to save the tokens (?). In that case, what is a good strategy for token invalidation (logout for example) ?

It also adds some information to the request for the upstream server

Does it also send the original tokens (specifically the id token) for the upstream server ?

Trojan295 commented 6 years ago

Yes, it's stateless, Kong datastore is not used. So if you would use this cookie in an another browser or from an another machine - it won't work. To invalidate the tokens you can make a call to root url /logout (http://<kong_host>/logout). This will trigger a call to the OIDC End Session Endpoint.

The original tokens aren't send to the upstream server, but the X-Userinfo header contains claims from the ID token (but without AS signatures).

Trojan295 commented 6 years ago

I created a issue #19 for the luck of documentation. @mderazon, @huikang, if you guys are playing with this plugin, it would be great, if you could try to help improve the README.md.

mderazon commented 6 years ago

If we start implementing our oidc auth with this plugin we'll help with the documentation, for sure.

BTW, is Nokia using this in production ?

Trojan295 commented 6 years ago

Yes, it is used in production by us

jeremyjpj0916 commented 6 years ago

Sorry to bother, but like others I am trying to learn about OpenID Connect, and I have gathered its a flavor of oauth 2.0 and jwt in combination to achieve a sort of decentralized authentication pattern(correct me if I am wrong with any of that). So how does your plugin differ from say : https://github.com/mogui/kong-external-oauth ? Because theirs seems to handle OpenID connect handshake as well correct? Further questions are as follows:

  1. Can ACL be applied alongside this plugin to get an extra second layer of separation by consumer authentication?

  2. Can this plugin be applied on top of individual API's directly and not at the global level like your first curl post? If so can you give an example?

  3. Is there anything you set on the {consumer-id}/plugins/{your-plugin} here that will set the proper authentication pattern required values to a specific consumer (much like Kong O-Auth 2.0 works?)

Sorry if some of these questions don't make sense for the access type, I am new to OpenID Connect!

Ideally I am looking to support Token based/OAuth 2.0/ and potentially OpenID Connect for authentication types with a Kong cluster.

Would love to connect about it if you have time. -jjustus@g.clemson.edu

Thanks!

Pinguwien commented 6 years ago

Hi there, @jeremyjpj0916 did you get answers for your last questions so far? Very good questions though, thanks! We are in nearly the same phase of evaluating keycloak/kong as Gateway/Auth-Solution for a scalable platform here at the moment. A good documentation would be so great!

Trojan295 commented 6 years ago

Sorry for a late response, but I missed the notification about a new comment.

@jeremyjpj0916

In practice, this plugin allows you to use an external OIDC Provider (Gluu, Keycloak) to protect APIs behind Kong and feed into them information about the users identity. So you don't have to use to built-in consumer mechanisms in Kong, but use a centralized solution, which could cover not only Kong.

It differs from https://github.com/mogui/kong-external-oauth, cause it implement OIDC, not OAuth2. OIDC is an extension to OAuth2, which introduces an identity layer to OAuth2.

In standard OAuth2 the Client does not have information about the identity of the Resource Owner. OIDC adds an JWT ID Token and Userinfo Endpoint to the Authorization Server, which allows the Client (called OIDC Relying Party in OIDC) to get information/claims about the Resource Owner. These can be username, email, address, phone number, roles, group, attributes etc.

  1. No, this plugin has no ACL support. It's only serving as a OIDC Relying Party and adds the Identity layer to the requests, which go to upstream APIs (see the X-Userinfo header, which contains the response from the Userinfo Endpoint from the OIDC Provider). But with this information you could implement your own access control (with an another Kong plugin or on the upstream API) using claims, which are in the Userinfo (eg. groups/roles/attributes). In fact, it would be a nice feature. Open up a issue for such functionality (RBAC/ABAC based on ID token claims)!
  2. Yes, it can. I will prepare some documentation with examples to show this.
  3. No. That's the point of this plugin: to use an external Authorization Server (OIDC Provider) and don't depend on Kong consumer management.
Pinguwien commented 6 years ago

@Trojan295 Thanks for the clarification! So...

for 1 you said: "No, this plugin has no ACL support...." - this means, there's no direct connection between keycloak clients and kong consumers, right? so you can't use it as another level of protection, instead it's just "use kong" or "use keycloak", right? I mean, the plugin "just checks if the token is valid", not that a specific token came from a specific client/consumer (which may require some mapping etc.)

That said, I think it is possible to use ACL alongside the plugin, you just have to make the prerequisite "kong handles authorization via acl, keycloak is used for authentication (login) only" - no?

(If no, is it NOT possible to use ACL to restrict consumers from accessing other APIs when using this plugin to check the validity of the token and restrict access when token is not vlid? why not? I don't think ACL and oidc tokens are interfering with each other in the first place)

Sorry for the detail-question, but I'm asking that because "use kong for authorization and keycloak solely for user login through various IDP" is our usecase here and it would be great to have a clear answer here :)

for 2: Docs would be great, thanks!

Trojan295 commented 6 years ago

@Pinguwien

The subject and preferred_username fields from the Userinfo Endpoint are in fact injected into Kong ctx variable, so they are available in other Kong plugins. This can be used to identify an Keycloak user in Kong. https://github.com/nokia/kong-oidc/blob/e5162954057bc76d420dd9d705f0ae5d782b9260/kong/plugins/oidc/utils.lua#L66

Instead of creating a user - consumer mapping you could make authorization based custom claims in the Userinfo Endpoint response.

Example: You define a list of attributes and define access policies based on them. Then you attach them to specific users in Keycloak and add this as a custom claim to the ID Token/Userinfo Endpoint. Kong-oidc fills the X-Userinfo header with the Userinfo response. You could write a plugin, which works after Kong-oidc, which uses those attributes in the X-Userinfo to evaluate your access policies. In this way you define access policies on Keycloak (which has a nice UI) and evaluate them on Kong.

Remember OIDC is an authentication layer, not authorization! For authorization you can use OAuth2 or develop you own mechanism. For advances authorization mechanisms take a look on UMA 2.0 (which is also an extension to OAuth2).

jeremyjpj0916 commented 6 years ago

Could the plugin not be enhanced to provide that consumer ACL capability by an option. After reading your thoughts(which helped a lot thanks a ton!) I see you could probably tie the Identities response (say email for example) to an existing kong consumer, say you make the consumers custom_id an email in the db, then your plugin can have the option to enable consumer validation.

Where it says okay I need to see if there is a consumer with this email address tied to his account and then if it finds that user make sure the ACL white list groups on his account contains the ACL group associated to the api white list.

Granted yes its a little extra code work and maybe not necessary in your use case. But as for open source community to give it the functionality to add that tie into ACL would be exactly what the masses need imo, take the validation away from API's and let it live in the gateway layer like Kong was designed for, and maybe make it configurable where the value it checks for from the ODIC's response does not just have to be an email but any one on of the informational values tied to its response.

What are your thoughts?

Trojan295 commented 6 years ago

Authorization is out of scope for this plugin. It's an authentication plugin, which implements the OIDC relying party in Kong.

If you want an authorization based on ACL using the information in this plugin you can achieve it by implementing an other plugin, which uses the information this plugin adds to the ngx.ctx. If you need more data from ID token in ngx.ctx create a new feature request in this repo on even make a PR! We highly appreciate any feedback/help here! :)

@huikang, @jeremyjpj0916 @Pinguwien @tsyrjanen, the PR with improved docs was merged. Can we close this issue?

tsyrjanen commented 6 years ago

@Trojan295 you have done great job. I vote to close this issue.

jeremyjpj0916 commented 6 years ago

@Trojan295 Sure lets get it closed up, thanks for your efforts into this!

meghprkh commented 6 years ago

Sorry for asking here like it was a help forum, but I am trying to configure this with google as the openid provider and the following is the config for the plugin

oidc

And the API is httpbin, screenshot from 2017-12-14 17-51-56

However as you can see that no X-UserInfo is being set. Am I doing anything wrong?

meghprkh commented 6 years ago

On looking at the error logs, I can see the following continuously happening

2017/12/14 14:49:49 [error] 414#0: *83693 [lua] openidc.lua:271: openidc_call_userinfo_endpoint(): accessing userinfo endpoint (https://www.googleapis.com/oauth2/v3/userinfo) failed: 20: unable to get local issuer certificate, client: 172.17.0.1, server: kong, request: "GET /api/anything/?state=0f5f148661f4cf9393f1da57a7e88277&code=4/AACKa-5sBcn6bd1vIePEgXAGIfU0GRBCCMEDWJj3dquZUY9JDtSG_LaJinwz2NljBO6_aHQPr54xcRYBP--tqno&authuser=0&session_state=2ca1a1d93e59f8b09395992b4c80ff950c6c17d0..5381&prompt=consent HTTP/1.1", host: "localhost:8000"

Even though ssl_verify is set to no. If it helps I am using the docker image based on centos. ca-certificates is installed and i can successfully curl to https://www.googleapis.com/oauth2/v3/userinfo

zandbelt commented 6 years ago

I believe you're running into https://github.com/zmartzone/lua-resty-openidc/issues/125 which would require a (significant) update of the lua-resty-openidc dependency for this plugin.

meghprkh commented 6 years ago

I tested as of now, I cant find any logout route and it says no API at /logout. Also I would like to configure this URL. How do I do this? Another issue I am facing is that when user logs out of another client in keycloak, the session expires and thus keycloak issues an error when trying to refresh access token, resulting in an error from kong-oidc. How do I solve this?

meghprkh commented 6 years ago

Also when I normally visit my main client, I can login/logout normally. But when I visit a page proxied by kong-oidc, I cant logout and keycloak keeps giving 400 bad request. Any help would be appreciated a lot. Thanks.

Trojan295 commented 6 years ago

@meghprkh I'm closing this issue, if you have still problems please open an another issue.

djabbar13 commented 5 years ago

Hi, I'm using your plugin with Ory Hydra as OIDC provider and I'm facing redirect_uri problem. I'd like to have much explanation of how to use it in my case:

Thanks

rush2subbu commented 4 years ago

On looking at the error logs, I can see the following continuously happening

2017/12/14 14:49:49 [error] 414#0: *83693 [lua] openidc.lua:271: openidc_call_userinfo_endpoint(): accessing userinfo endpoint (https://www.googleapis.com/oauth2/v3/userinfo) failed: 20: unable to get local issuer certificate, client: 172.17.0.1, server: kong, request: "GET /api/anything/?state=0f5f148661f4cf9393f1da57a7e88277&code=4/AACKa-5sBcn6bd1vIePEgXAGIfU0GRBCCMEDWJj3dquZUY9JDtSG_LaJinwz2NljBO6_aHQPr54xcRYBP--tqno&authuser=0&session_state=2ca1a1d93e59f8b09395992b4c80ff950c6c17d0..5381&prompt=consent HTTP/1.1", host: "localhost:8000"

Even though ssl_verify is set to no. If it helps I am using the docker image based on centos. ca-certificates is installed and i can successfully curl to https://www.googleapis.com/oauth2/v3/userinfo

Hey bud , did you ever get this issue resolved ?