Restrict service call to other services only

58 views
Skip to first unread message

Bear

unread,
Feb 28, 2018, 8:13:48 AM2/28/18
to Lagom Framework Users
Dear all,

I'm trying to restrict the usage of some route of one service to other services only. In other words, the only allowed clients for this service should be my other Lagom services.
Is this achievable reliably using Lagom and if yes how ?

Thanks in advance for your help !

Tim Moore

unread,
Feb 28, 2018, 7:43:18 PM2/28/18
to Bear, Lagom Framework Users
What is your goal here? Is this intended to be a security measure, or only to prevent mistakes where someone accidentally makes a network call where a local method call could be used?

If it's not required to be secure, one thing you can do is check the Principal on the request in a HeaderFilter. As that documentation page mentions, by default Lagom installs a UserAgentHeaderFilter. This sets the "User-Agent" header on outgoing client requests to the service name, and on incoming server requests, translates it to a ServicePrincipal attached to the request. Then, you could check the ServicePrincipal in your call to make sure the name doesn't match the current service.

(You didn't mention whether you're using Java or Scala, so I linked to the Java documentation, but the same applies in Scala).

However, User-Agent headers can be easily forged, so this isn't a secure way of checking.

If you need security, you will need some way to verify the authenticity of the request, perhaps using a public key infrastructure. However, anyone who has the ability to change the service to make it issue unauthorized requests to itself could also change it to remove or subvert the check. Is the concern that this service makes requests that are parameterized by data passed in to it? I'd need a better understanding of the threat model to offer better advice.

Can you explain the requirement with more detail?

Best,
Tim

--
You received this message because you are subscribed to the Google Groups "Lagom Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lagom-framework/6d667e22-33b1-42d4-af68-852ddc637f49%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Tim Moore
Lagom Tech Lead, Lightbend, Inc.

Bear

unread,
Mar 3, 2018, 1:20:17 PM3/3/18
to Lagom Framework Users
Thanks for your answer !

I want to ensure security (some routes necessary for inter-service communication could reveal sensitive information) and avoid abuse of usage (internal API routes which shouldn't be called too often because they depend on external usage-restricted routes, and as such my clients should be able to call the directly).
In short I want to ensure securely that the caller of one particular service call is one of my Lagom services.

I also thought about using a secret token (password) that's hardcoded into my services (loaded at startup for example from configuration) and to put it into the headers of the requests. Would this solve the issue ?

By the way I'm using Lagom 1.4.0 in Scala.

Le jeudi 1 mars 2018 01:43:18 UTC+1, Tim Moore a écrit :
What is your goal here? Is this intended to be a security measure, or only to prevent mistakes where someone accidentally makes a network call where a local method call could be used?

If it's not required to be secure, one thing you can do is check the Principal on the request in a HeaderFilter. As that documentation page mentions, by default Lagom installs a UserAgentHeaderFilter. This sets the "User-Agent" header on outgoing client requests to the service name, and on incoming server requests, translates it to a ServicePrincipal attached to the request. Then, you could check the ServicePrincipal in your call to make sure the name doesn't match the current service.

(You didn't mention whether you're using Java or Scala, so I linked to the Java documentation, but the same applies in Scala).

However, User-Agent headers can be easily forged, so this isn't a secure way of checking.

If you need security, you will need some way to verify the authenticity of the request, perhaps using a public key infrastructure. However, anyone who has the ability to change the service to make it issue unauthorized requests to itself could also change it to remove or subvert the check. Is the concern that this service makes requests that are parameterized by data passed in to it? I'd need a better understanding of the threat model to offer better advice.

Can you explain the requirement with more detail?

Best,
Tim
On Wed, Feb 28, 2018 at 11:43 PM, Bear <sono...@gmail.com> wrote:
Dear all,

I'm trying to restrict the usage of some route of one service to other services only. In other words, the only allowed clients for this service should be my other Lagom services.
Is this achievable reliably using Lagom and if yes how ?

Thanks in advance for your help !

--
You received this message because you are subscribed to the Google Groups "Lagom Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framewo...@googlegroups.com.
To post to this group, send email to lagom-f...@googlegroups.com.

Tim Moore

unread,
Mar 4, 2018, 8:31:51 PM3/4/18
to Bear, Lagom Framework Users
Thanks for the clarification... I apologize: I totally misinterpreted your question in my first response. This makes perfect sense now. It's very common to have some service calls that are internal only, and others that are externally accessible.

The most common way to handle this is to avoid exposing your services directly to external clients in the first place. Instead, keep them on a private network where they are only accessible to each other. Then, have a proxy server at the edge of the network, with a public IP that is accessible to external clients, and a private one on your internal private network. This proxy server can forward the externally-accessible routes to the appropriate internal back-end services. This deployment pattern is often known as an API gateway or service gateway.

Lagom's development mode implements a simple service gateway that can be used this way. When you "runAll" and then connect to http://localhost:9000, you are using the service gateway. You can configure the routes to forward to each service using service ACLs in the service descriptor. If you follow the examples you see in the docs, you might be calling "withAutoAcl(true)" in your service descriptor. This means: make all service calls externally accessible and forward them all from the gateway, which is not what you want in your case. Instead, you can call withAcls and pass a list of ServiceAcl objects, constructed using one of the factory methods in the companion object. This allows you to specify regular expressions to match against the path, and optionally the HTTP method you wish to allow.

In production, the specifics will vary depending on the deployment environment you're using. In Kubernetes, this concept is called Ingress and is usually implemented using nginx. AWS offers a couple of different solutions: API gateway and Application Load Balancer. These have somewhat different feature sets and intended use cases, and you can use them separately or together. If you are self-hosting without using Kubernetes, you can set up a server such as nginx or haproxy to perform this role.

For a lot of people, this level of security is enough: if the services aren't available via the network from the clients, then you can be pretty sure they won't be able to call the internal service routes. If you want an extra layer of security (for example, to protect against misconfiguration of the gateway, or a network intrusion) then you can implement additional measures.

A secret token in the headers like you describe is a perfectly fine, simple approach. The main advantage is the simplicity of implementation. It does have a couple of disadvantages:
  1. It won't help you determine which service issued the request, if you need to audit that information. For that, you would need per-service tokens.
  2. If the secret is somehow compromised, you'll need to change it everywhere, all at once. This will probably require taking your entire system offline for redeployment.
  3. If you are concerned about network security, then a cleartext token sent with each request is a risk. An attacker could potentially sniff network traffic to obtain the token.
If you're worried about any of these, a more secure approach would be to use a public key infrastructure that allows each service to be issued with its own key pair. Requests can include a client signature (for example, using JWT) that can be verified by the receiving service. Using a unique key pair per service allows you to securely identify the specific service making the request, and rotate an individual service's key pair without having to change all the others. Use of asymmetric encryption means that no secrets need to be transmitted over the network. The tradeoff is that this is much more complex to set up and administer, and you will need a solution to handle key revocation.

Best,
Tim

To unsubscribe from this group and stop receiving emails from it, send an email to lagom-framework+unsubscribe@googlegroups.com.
To post to this group, send email to lagom-framework@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/lagom-framework/71a5ab7c-7dfc-4309-849b-9d53d0d766d1%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages