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

Pass back claims as headers #6

Open
carlpett opened this issue Sep 3, 2019 · 3 comments
Open

Pass back claims as headers #6

carlpett opened this issue Sep 3, 2019 · 3 comments

Comments

@carlpett
Copy link
Owner

carlpett commented Sep 3, 2019

As suggested on Slack:

Is there some mechanism for passing information (eg user email extracted from JWT) back to nginx, and for nginx to include that information in requests to backend (eg header)?
Like https://github.com/kubernetes/ingress-nginx/blob/29c5d770688b04d0a8beedf70aebd76990332d56/docs/examples/customization/external-auth-headers/deploy/echo-service.yaml#L52

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: public-demo-echo-service
  annotations:
    nginx.ingress.kubernetes.io/auth-url: http://demo-auth-service.default.svc.cluster.local?code=200
    nginx.ingress.kubernetes.io/auth-response-headers: UserID, UserRole
@ellieayla
Copy link

Assume some backend service can handle read and write of some data for many users, as is normal in multi tenant systems. For this example, we'll assume a User Profile microservice, where a client can read/write user profiles. The following is simple AuthZ logic:

  • Every user profile has its own absolute path, of the form /user/{id}
  • The user can update their own profile
  • An administrator can update any profile
  • Anyone can read any profile

Let's assume the backend User Profile microservice already exists, and is already enforcing the above logic. It is doing so by parsing the JWT from the Authorization header's bearer token, and extracting the user's identity from the list of claims, the comparing that identity against the current resource.

The responsibility for extracting the user identity from the JWT is being moved to nginx-subrequest-auth-jwt. The responsibility for comparing identity against resource AuthZ could also be moved, or could remain as-is. This issue assumes the latter is desirable.

The backend microservice could explicitly trust provided headers, and its AuthZ logic be reduced to:

@route('/user/{id}')
def handle_write(request):
    if request.headers.get('UserID') == request.id or request.headers.get('UserRole') == 'mega_admin'):
         # do write
    else:
         raise NoPermissionError()

By trusting someone else to handle AuthN enforcement, the User Profile microservice cannot be securely run without that someone else. This grants advantages and disadvantages:

  • could be black-box tested without issuing or parsing any JWT tokens (or even worse, having a no-auth mode just for testing). A testcase can trivially make requests with any user id or role claims it wants.
  • anyone who can issue requests with arbitrary headers directly to the User Profile microservice (eg another pod) can impersonate any user or role claim it wants.

Such downsides could be mitigated by teaching the User Profile microservice some method to trust the ingress controller (eg, HMAC-signing the headers) but down that path lies a reimplementation of JWT, at which point there's no point in using nginx-subrequest-auth-jwt.

@carlpett
Copy link
Owner Author

carlpett commented Sep 4, 2019

Thanks! Would you see which headers to be returned as something you'd configure statically for the nginx-subrequest-auth-jwt instance, or something that could be passed into the validation request? Or could it be either?
Compare with how there is a static and queryString mode for the claims to validate.

@ellieayla
Copy link

I can see that desire going either way. The set of claims received by multiple Ingress Rules is probably constant for one app, but could be varied across multiple apps. The application I'm thinking of would probably only need a max of 5? claims shared by all microservices. If the auth-backend sanely handled missing/optional claims (leave out those headers?) then the set could happily be constant.

While I probably wouldn't use queryStringesque mapping rules, I can see someone else wanting it later.

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

No branches or pull requests

2 participants