Haufe-Lexware / wicked.haufe.io

An API Management system based on Mashape Kong
http://wicked.haufe.io
Other
123 stars 37 forks source link

JWT plugin config (RS256) #92

Open ssnippets opened 6 years ago

ssnippets commented 6 years ago

Kong requires JWT consumers to be configured with a public key when using RS256. Is there a way to incorporate input of public keys or consumer configuration for a plugin like JWT in the config files so the kong adapter sends them when it's setting up?

In order to generate the JWTs, access to the iss field will also be needed. It would be nice if one consumer could accept JWTs for the entire Kong configuration

ssnippets commented 6 years ago

I have some sample code for interfacing with Kong directly (bash script), I can take a stab at updating the adapter, some direction from someone with a bit more experience in the codebase would be helpful (any pointers?).

#Create a consumer for JWTs:
curl -d "username=jwt" -k $PROTO://$KONG_API/consumers

#get the ID for the consumer:
JWT=$(curl -X GET -k $PROTO://$KONG_API/consumers/jwt | jq .id | sed "s/\"//g")

# ACLs, if needed
curl -k -X POST $PROTO://$KONG_API/consumers/jwt/acls \
    -d "group=test_group"

#Set up the plug-in for an API.
curl -k -X POST $PROTO://$KONG_API/apis/$API_NAME/plugins \
  -d "name=jwt" 

#Send up the public and private keys which are stored in jwt/key.pem and jwt/pubkey.pem:
RET=$(curl -k -X POST $PROTO://$KONG_API/consumers/$JWT/jwt \
  -d "secret=$(cat jwt/key.pem | sed 's/$/\\n/' | tr -d '\n')" \
  --data-urlencode "rsa_public_key=[[
$(cat jwt/pubkey.pem)
]]" \
  -d "algorithm=RS256")

#this is the issuer that will be validated via Kong and needs to be a claim when generating JWTs for use in Kong,:
JWT_KEY=$(echo $RET | jq .key)
echo "JWT KEY: $JWT_KEY" # This value needs to be in the 'iss' claim for jwts

#I write it out to a file so I can read it in when generating JWTs. There needs to be a method to retrieve this key:
echo $JWT_KEY |sed 's/["]//g' |tr -d '\n'  > jwt/iss.dat
ssnippets commented 6 years ago

Also, this might help, generation of the key pairs can be done as follows:

openssl genrsa -out key.pem 1024
openssl rsa -in key.pem -pubout > pubkey.pem
DonMartin76 commented 6 years ago

Hi @ssnippets - Germany has two public holidays in a row this week (woo!), so I missed out on this a little. It's perfectly possible to just add a plugin to the API configuration, that's intended use. If you then just add a ${JWT_KEY} in the configuration of the plugin, the Kickstarter will pick it up and display that env var in the "Environments" section.

There you can then paste your private key and have the Kickstarter encrypt it using the deployment key. Alternatively, you can inject the key as an env var "from the outside" to the portal-api container; the Portal API will replace it correctly inside the plugin configuration.

I must admit I haven't been using JWTs much, and neither wicked nor Kong as JWT authoring capabilities. It might be a good idea to add that kind of capability to a default implementation of an Auhtorization Server.

ssnippets commented 6 years ago

Hope your holidays went (or are going?) well. Thanks for the tip. I still think there might be an issue with retrieving the issuer. I'll give your suggesting a whirl and let you know how it goes. Thank you.

DonMartin76 commented 6 years ago

Still going on, and fine, thank you :-D

Yes, that's what I meant, you will still need to query Kong to get the issuer when crafting the JWT. This could be made a part of the Kong Adapter, or in the future, of a Kong OAuth2 adapter library, as we are planning to remove the stateless end points from the Kong Adapter in the future (the code is almost done, but there is still quite a way to go until wicked 1.0).

Actually, crafting JWTs could be a part of that library, that sounds like a good idea.

ssnippets commented 6 years ago

Great. That sounds viable. As a side note, I'm working on a DC/OS deployment and have most of my marathon json files set up. I'll share a sample deployment when I get it up and running, hopefully it can help with your documentation.

And again, thank you.

ssnippets commented 6 years ago

I've tried a few things but am still not quite there. The plugin config works to set up the plugin but not the consumer. I'm assuming I'm still missing something since key-auth works similar to the jwt plugin:

  1. add the plugin to the api
  2. set up the consumer

Everything I put under config seems to be getting sent to the api config $KONG/apis/{api}/plugins though which returns with an error for unknown values:

{ 'config.secret': 'secret is an unknown field',
  'config.rsa_public_key': 'rsa_public_key is an unknown field',
  'config.algorithm': 'algorithm is an unknown field' }

What I would like, if it exists, is to be able to send config parameters to the consumer setup $KONG/consumers/{consumer}/jwt to provide the JWT setup, which should look something like:

    {"rsa_public_key": "${JWT_KEY}",
    "secret": "${JWT_PRIVATE_KEY}",
    "algorithm": "RS256"}

Have I just not found the right way of configuring Wicked or am I in uncharted waters?

DonMartin76 commented 6 years ago

Ah, you're right. Kong's JWT implementation requires a consumer to be resolved. I wasn't aware of this from the top of my head, but you're right.

This is not possible OOTB with wicked, let us think about how that could work out. In principle this might be a third way of authenticating a consumer, in addition to key-auth and oauth2.

Hum hum hum.

ssnippets commented 6 years ago

OK good, I'm not just failing miserably 😄 ... thanks for taking a look. I'll take a look from my end and see if I can add that in... I need to get acquainted with the code a bit more though.

DonMartin76 commented 6 years ago

I’ll also keep it in mind. You will also need an AuthZ Server of some sorts. And it should be done using OAuth2, albeit not with Kong‘s oauth2 plugin. Let’s keep in touch on this.

ssnippets commented 6 years ago

I created a PR yesterday as a quick fix for the specific issue I was having with the jwt plugin, but in thinking about it a bit more, that solution is really not all that useful for the general problem of plugins that need consumers to be configured. My thought is that ideally, the general "plugin" spec allows an object to be passed to consumers that are created when using it.

DonMartin76 commented 6 years ago

Yes, it's not ideal. It could be a patch for your specific problem, but it's not a generic solution. I'll try to think more about it next week.

DonMartin76 commented 6 years ago

So, I think this would be "the real" solution to enabling JWT with wicked:

This would fit nicely into the concept of wicked 1.0 (see the current collection of design documents). The default AS could support both plain OAuth2 with opaque tokens registered with Kong, or JWT tokens; the Kong Adapter would configure the APIs and consumers accordingly and automatically, so there would be no need for a custom plugin configuration.

What is your timeline for this? I don't have an ETA on wicked 1.0 just yet, but would aim to release an alpha or beta in November (no promises, depends on other things, like my current project).

Thoughts?

ssnippets commented 6 years ago

A couple of things that come to mind:

I wonder though, if this isn't functionality that would be better suited for a Kong plugin instead of at the Wicked level -- perhaps a fork of the oauth2 plugin that allows for JWT generation instead of the tokens.

I like what you've built for the configuration aspect: defining APIs, and managing subscriptions. I think you might get a bit more flexibility out of the system by making the custom plugin configuration a bit more robust, allowing consumers to be configured the same way you pass in parameters to the plugin.

I don't have any sort of urgency on this. The patch that I applied works for what I need it to do for now. I would love to help if I can -- I see a lot of good coming from this project. Let me know if I can be of any assistance.

DonMartin76 commented 6 years ago

Good points. The former (payload) is something that has to be solved for the Authorization Server anyway, and my plan was to have a set of defaults which are always added (like name, email, ids and such) and then add a "plugin" which can be "asked" for additional values.

This is needed for deciding on scopes anyway, and it fits quite nicely for the additional claims in the JWTs as well.

The secrets are just configuration, as far as I see it, and can be added without much effort to the existing configuration mechanism.

Not sure about the Kong plugin part, will give that some more thought. The thing with the oauth2 plugin is that it generates opaque tokens, and that they are "registered" with Kong. Which is kind of the thing which is not necessary with JWT. On the other hand, you can't do completely without Kong either, as you need the iss when crafting the token.

ssnippets commented 6 years ago

One thing on the iss field, you can pass that in to the Kong config, so you can set up an issuer for your JWT authoring tool. If you don't pass it in, it gets automatically generated. that field ends up being the key field that is sent to the consumer.

miguelpoyatosmora commented 5 years ago

I would like to know the status of the JWT authentication of the consumers with kong (not kong with the upstream api) handled by Wicked. Is currently JWT an alternative to key-auth and oauth?

Many thanks, Miguel

DonMartin76 commented 5 years ago

Currently it's not really supported; I have given this quite some thought, and currently the primary use cases are not needing JWTs, and/or they are not better using JWTs than opaque tokens.

From my point of view, JWTs shine for distributed authorization scenarios where you use a separate authorization server to author JWTs for use with an API which is located somewhere else. This is not the main use case for wicked: Acting as an API Gateway in front of your APIs.

There could be a separate way of authorizing using JWTs, but I currently don't see the real benefit of it in the current architecture. It would make sense as a separate feature of the Authorization Server (much like Auth0 does it), but IMHO not as a default solution for wicked. The drawback of not being able to revoke the token is in my eyes difficult, or the need of adding blacklists for this, is not something I would want to enforce.

But: Please describe your use cases, it's more than possible I am missing something obvious. Thanks for pitching in in the discussion!

miguelpoyatosmora commented 5 years ago

A use case would be when an existing client coupled to an API that uses JWT and you want to put Wicked+Kong in the middle without changing the client code. I don't thing its a big change for the client, but you never know.

I share your point of view on JWT having redundant functionality when used with Wicked. I will try to collect more requirements and to adapt clients to key-auth.

Many thanks for the quick response!