Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is token access possible for APIs when using Auth Host Mode #119

Closed
stevegroom opened this issue Apr 30, 2020 · 6 comments
Closed

Is token access possible for APIs when using Auth Host Mode #119

stevegroom opened this issue Apr 30, 2020 · 6 comments
Labels
question Further information is requested

Comments

@stevegroom
Copy link

I have Traefik 2/Keycloak/TFA solution running.
The config is using auth host mode and I get the expected re-direction to keycloak.mydomain/auth to supply credentials and re-direction back via auth.mydomain/_oauth to myapp.mydomin.

What I am trying to do now is to find some way to create a long lived access token to allow me to consume the traefik API with node-red (i.e. parse the JSON returned from https://traefik.mydomain/api/http/routers).

So far I have

client_id
client_secret
username
password 
etc. 

I want to call authentication_endpoint and/or token_endpoint generate a long lived (bearer?) token.

I want to add the resulting code to my node-red http call as a header or parameter:

https://traefik.mydomain/api/http/routers?whattoken=whatvalue

Can this be achieved and what are the general steps needed?

I'll happily document the scenario as an example if I get it to work.

best regards
Steve

@thomseddon
Copy link
Owner

The technique I use for this is to create static tokens and then apply them in rules, for example:

# Allow based on access token in query
rule.allow_api1.action = allow
rule.allow_api1.rule = Host(`traefik.mydomain`) && Path(`/api/http/routers`) && Query(`whattoken `, `whatvalue`)


# Allow based on access token in header
rule.allow_api2.action = allow
rule.allow_api2.rule = Host(`traefik.mydomain`) && Path(`/api/http/routers`) && Headers(`X-whattoken `, `whatvalue`)


# Allow based on access token in query or header
rule.allow_api3.action = allow
rule.allow_api3.rule = Host(`traefik.mydomain`) && Path(`/api/http/routers`) && (Query(`whattoken `, `whatvalue`) || Headers(`X-whattoken `, `whatvalue`))

Would that work?

@thomseddon thomseddon added the question Further information is requested label Apr 30, 2020
@stevegroom
Copy link
Author

Hi Thom,
thanks for getting back to me.

When you say create your own static tokens - are you using keycloak to generate them?

For you proposal, I can see that this can work in principle but I feel that this does not respect the segregation of duties though - as Traefik will be authorizing the request itself.

I found this article http://www.bubblecode.net/en/2016/01/22/understanding-oauth2/#Authorization_header#Access_token_usage helped my understand what I think I should be doing - i.e. adding Authorization header.

In my current setup I need to have a cookie called _forward_auth as the authorization. What I want is to have a bearer token so that i can make calls like this:

curl --location \
    --request GET 'https://whoami1.mydomain \
    /?access_token=IN0q...5RS_Q%3D|1590905678|email@address' \
    --header 'Authorization: Bearer IN0q...5RS_Q=|1590905678|email@address'

i.e. Either a URI parameter acess_token or an Authorization header

Is this possible with traefik_forward_auth?

best regards
Steve

@stevegroom
Copy link
Author

stevegroom commented May 7, 2020

Hello @thomseddon,
I have followed this thread https://keycloak.discourse.group/t/how-to-use-api-keys-with-keycloak/2390/14 and received a suggested flow for how to obtain and use a token.

To summarise

curl -v -d "client_id=keycloak-client" -d "username=user@domain.com" 
  -d "password=password" 
  -d "grant_type=password" 
  -X POST "http://localhost:8080/auth/realms/realm-name/protocol/openid-connect/token" | 
jq -r .access_token;

This retrieves the access_token which is added to the Authorization: Bearer header in the following call:

curl --location --request GET 'https://whoami.mydomain/api/http/routers' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer eyJhbG...L_J8g' \
--header 'Cookie: _forward_auth_csrf=958ae1cb0c5ff311123b81daad0052a5'

This call results in a redirection to the Keycloak logon scheme.

Can you tell me if this should be workable with the traefik_forward_auth setup?

@thomseddon
Copy link
Owner

Unfortunately, the only way rules can work is if the token is static (i.e. doesn't change once generated and doesn't need to be dynamically cycled), if this fits your situation you can generate the token, then do:

# Allow based on access token in header
rule.allow_api2.action = allow
rule.allow_api2.rule = Host(`traefik.mydomain`) && Path(`/api/http/routers`) && Headers(`Authorization `, `Bearer eyJhbG...L_J8g`)

However, if you would like the token to be generated and used dynamically, then I think this goes beyond the scope of how this app works.

A better approach may be to build a direct integration between your application and keycloak, as shown in the api key example: https://github.com/zak905/keycloak-api-key-demo/blob/master/rest-api-service/index.js (I'm assuming the client is your own application, if not it would be good to know what it is to understand your use case?).

You could still keep traefik-forward-auth for other services in the cluster, but either don't apply the middleware to your API application, or create a rule to allow requests through traefik-forward-auth, and handle the authentication yourself in the client :)

@stevegroom
Copy link
Author

Thanks' for the feedback Thom. I'll work on getting nodeRed built in authentication working instead.

best regards
Steve

@thomseddon
Copy link
Owner

No problem, this is an interesting angle - in the future I hope to add different types of providers and perhaps an "api-key" provider would make sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants