5

I am planning to implement JWT authentication on my micro-services to achieve zero trust architecture. User will generate a JWT token through front end micro-service. Each subsequent request will contain this JWT which will be forwarded to backend services so the service can authenticate the user on it's own instead of taking a simple user id from front-end service. The scenario fails in two conditions

  • User initiates a call on front end service which generates a long list of steps to be performed on backend services sequentially. The JWt token will eventually expire and the sequence of steps will stop as backend services will not authenticate further requests from frontend with an expried token
  • A backend service starts some process on user resource through an internal process. e.g. Delete user server if the invoice is unpaid.

In both of the scenarios user will not be available to generate a new JWT token through login credentials. Should I implement one time and purpose specific tokens in addition to JWT to resolve these issues or is there a better alternative?

1
  • It should be noted that this doesn't quite sound like zero-trust. You're trusting at least two things here: that the JWT signing key is not compromised, and that the request as "forward to backend services" has not been tampered with prior to the forwarding. Typically so-called "zero-trust" accepts the first risk, but expects your client to be communicating directly with the backend services without prior TLS termination. True zero-trust requires end-to-end encryption of not only the connections but also the data, such that it is opaque to the server and impossible for the server to modify.
    – CBHacking
    Aug 27, 2022 at 7:28

2 Answers 2

0

tl/dr: it's okay to have the backend accept a user id as part of a zero-trust architecture. The more important part is that your services must authenticate themselves to the backend, and the appropriate parts of the backend should only accept requests from your services (not from end-users). As a result your issue is trying to use the auth token of an end-user for services that the end-user isn't supposed to access directly. Let your services authenticate themselves with the backend, and then it's perfectly fine to pass along a user id.

Who is a "user"?

I think the key is that you're confusing who the "user" of some of your backend systems is.

This is most clear with your second example: deleting an inactive user. This is a system-only process. The user will never trigger this action themselves. The backend is the "user" performing the action, even though a user account is being affected. As a result it doesn't really make sense in the first place to be using the user's access token to delete the user. It's not like the user is ever going to be making these requests to the backend themselves. Indeed, user's should not be able to access these endpoints anyway. If somehow a user managed to access the backend to try to delete their account, their access token should be rejected - this endpoint is intended for system use only, (presumably) not for users to delete themselves. Therefore, by using the user's auth token to perform these system actions, you're authenticating as the wrong "person".

The situation is a bit more murky with your first example, because it is the user who makes an initial request which triggers the later actions. However, the overall situation seems is still the same anyway - a backend process is taking action on the user's data. The "user" of this system is not the actual end user, but is instead part of your own system. It just happens to be acting on behalf of your users.

In short, if you have backend services that are not meant to be invoked directly by users, then those services shouldn't accept the user's access token.

So what to do?

So how do you implement a zero-trust system? Naturally, the same way you are trying to do it - you're just authenticating as the wrong person. It's not the user that needs to authenticate itself to the backend, but rather it is whatever service is making use of the backend that needs to authenticate itself. This may or may not be with JWTs. It may be a simple matter of having an authentication token that only the "cron" service knows, and which it uses to authenticate itself with your backend. Those details are up to you.

However, I think that's the only real answer. These services need their own way to authenticate themselves with the relevant parts of your backend, and those parts of the backend should only accept requests from your authenticated services - not from end users with end-user JWTs. You'll obviously have to build the authentication method for your services in a way that covers issues with credential rotation if relevant. However, since you won't be using the user's password as part of that process, that won't be a concern.

0

In practice good zero trust relies on back-to-back authentication + user signed grants.

Back-to-back authentication

Service authentication grantee that each backend interacts only with allowed set of backends (APIs). Risks of reusing client grants from untrusted clients in the service network / irrelevant backends are anticipated. It also allows you to create authoritative services that may perform certain actions on behalf of a user. It is a usual scenario to create ever-lasting/cron jobs.


JWT implemetation of back-to-back authentication

Tokens make use of asymmetrical cryptography. Each service has a private key that is used to sign a service token.

Service token structure:

  • source backend
  • destination backend
  • timestamp

Each backend specifies allowed list of sources and each source is mapped with the public key to validate tokens.

All back-to-back queries are performed with service tokens.


Achieving ZTP - User authentication

As soon as we achieved zero trust principles in service communication, we now want to restrict backends from impersonating users without real user issuing a command. And that is where user tokens and you scheme appear.

User initiates a call on front end service which generates a long list of steps to be performed on backend services sequentially. The JWt token will eventually expire and the sequence of steps will stop as backend services will not authenticate further requests from frontend with an expried token

The backend authorized to perform "a long list of steps" validates that the user is real by checking JWT signature using client's public key. As soon signature is valid it may now schedule the operations.

By giving a service an impersonation privilege we basically replace user authentication with the service authentication. If using encrypted storage with the user key, service would have to prepare all the data required for the flow at the moment of user interaction.

Hardenings

For long-lasting (or cron-like) jobs, service might be given a permission to impersonate user under certain scope of actions. In this scenario user's JWT token grants specific action, regularity and parameters of the job and never expires. It is worth implementing a revoke policy by issuing and unique identifiers to the JWT and maintaining the list of revoked ones or providing expiry with the ability to refresh the token.

Useful links:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .