[keycloak-dev] Some community feedback & service-to-service calls

Thomas Darimont thomas.darimont at googlemail.com
Thu Oct 26 17:57:29 EDT 2017


Hello Keycloak Team,

sorry for the (again long email)
TLDR:
- some community feedback
- people want examples / guidelines for secure service to service
communication
- Ideas for a blog post about that

---

This week I gave a talk about Keycloak at a small Java conference
in Düsseldorf / Germany: jcon.one.

In my talk I gave a brief overview on Keycloak and explained how SSO
via OpenID Connect works in detail. I also explained and briefly showed
how to work with the various token types e.g. how to query a bearer-only
API backend from a confidential client. I also demonstrated the
KeycloakInstalled-adapter, which apparently isn’t shown very often.
The talk was very well received.

During the days after the talk I got a lot of questions about Keycloak and
in particular
about how general service-to-service communication could be secured by
Keycloak.

I explained that there are some options like using
service-accounts or explicit technical user accounts to represent a service
which can obtain AccessTokens by itself and use those tokens to access
other
services secured by one of the various Keycloak adapters.

However many folks didn't seem to be aware of those options.
I think the reason for this is because although many articles
about Keycloak describe how to secure a common web application,
[perhaps with a SPA frontend and an API backend which gets accessed via an
AccessToken] one (IMHO) hardly finds articles with some detailed
discussions about how to properly secure service-to-service communication.
E.g. some mentioned scenarios were
- service calls another service on it's own (cron job)
- ... or triggered by an event or some messaging system.
both without direct user interaction.

In the examples project there is also (only?) one example about
using service accounts which looks a bit verbose:

https://github.com/keycloak/keycloak/blob/master/examples/demo-template/service-account/src/main/java/org/keycloak/example/ProductServiceAccountServlet.java#L108

I think a blog post about "Best practices for securing service-to-service
communication with keycloak" would be a good topic for the Keycloak blog.

I think one should highlight some APIs like the KeycloakAdmin Client API
which makes it fairly easy to retrieve tokens for the client_credentials
grant.

E.g:
    Keycloak keycloak = KeycloakBuilder.builder() //
      .serverUrl("http://localhost:8081/auth")
      .realm("service-to-service")
      .clientId("service-a")
      .clientSecret("73e7a71a-015e-4896-80ae-8e39ccb41deb")
      .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
      .build();

    System.out.println(keycloak.tokenManager().getAccessTokenString());

Another point could be when an AccessToken should/needs to be verified
(e.g. via RSATokenVerifier).

One could also show the differences between the two approaches of using a
service-account and a "technical" user account.

Service Account:
- Enablement: Whole Service or just Service Account can be enabled /
disabled
- Credential: Service Account uses client credential
- Username: service-account-${client_id}
- Email: ${username}@placeholder.org
- Attributes: In datamodel but not exposeable to tokens
- Password Policy: does not apply
- Bruteforce Protection: does not apply
- Credential handling: visible in AdminConsole
- Grant type to obtain AccessToken: client_credentials
e.g.:
curl -X POST \

http://localhost:8081/auth/realms/service-to-service/protocol/openid-connect/token
\
  -d 'grant_type=client_credentials' \
  -d 'client_id=service-a' \
  -d 'client_secret=1e1ebe68-96f2-4dca-bda8-03df44d3be13'


Technical User Account:
- Enablement: User can be enabled / disabled
- Username: arbitrary
- Email: arbitrary
- Attributes: arbitrary attributes can be exposed to tokens via
ProtocolMapper
- Password Policy: applies
- Bruteforce Protection: applies
- Credential handling: hidden in AdminConsole
- Roles: can be assigned arbitrarily
- Grant type to obtain AccessToken: password -> needs Direct Access Grants
enabled
e.g:
curl -X POST \

http://localhost:8081/auth/realms/service-to-service/protocol/openid-connect/token
\
  -d 'grant_type=password' \
  -d 'client_id=admin-cli' \
  -d 'username=svc-onboarding' \
  -d 'password=secret'

When using technical user accounts it is IMHO advisable to prefix the
username of the
service users to ease differentiation between real users and "technical"
users, e.g.
"svc-onboarding", "svc-shipping".

I'm still undecided which of these approaches is best but I'm currently
leaning towards 1) for simplicity but 2) for security....

Another thing that I found:
One can define some kind of "locked-down client" that only allows
client_credentials grants
to obtain AccessTokens / RefreshTokens(IMHO).

To do that one needs to set "Standard Flow Enabled", "Implicit Flow
enabled",
"Direct Access Grants enabled" to "off" but "Service Accounts enabled" to
"On".

One could also describe how such clients could protected, e.g.
"bearer-only" or a
"confidential" client with autodetect-bearer set to true protected by one
of
the many Keycloak adapters.

Another thing to note is that using a secured channel like TLS for the
communication
between two services is IMHO still a good idea.

Cheers,
Thomas


More information about the keycloak-dev mailing list