Security for Microservices with Spring

Dave Syer, 2014
Twitter: @david_syer
Email: dsyer@pivotal.io

(Security for Microservices with Spring)

Agenda

Introduction

job-trends

What Are the Security Requirements

Stop bad guys from accessing your resources

Identity and permissions:

HTTP Basic Authentication

Example:

    $ curl "https://$username:$password@myhost/resource"

Simple Service

@Grab('spring-boot-starter-security')
@RestController
class Application {

   @RequestMapping("/")
   def home() {
      [status: 'OK']
   }

}

So what's wrong with that?

Certificate Based Security

Example:

$ curl -k --cert rod.pem:password https://localhost:8443/hello


https://github.com/SpringOne2GX-2014/microservice-security/tree/master/certs

So what's wrong with that?

Custom Authentication Token

https://github.com/SpringOne2GX-2014/microservice-security/tree/master/pairs/spring-session

So what's wrong with that?

OAuth2 Key Features

So what's wrong with that?

OAuth2 and the Microservice

Example command line Client:

$ curl -H "Authorization: Bearer $TOKEN" https://myhost/resource

Simple Resource Server

@EnableResourceServer
class ResourceServer {
    @Bean
    JwtTokenStore tokenStore() throws Exception {
        JwtAccessTokenConverter enhancer = 
            new JwtAccessTokenConverter()
        enhancer.afterPropertiesSet()
        new JwtTokenStore(enhancer)
    }
}

N.B. in a real system you would have to configure the verifierKey (or use JdbcTokenStore)

Simple Authorization Server

@EnableAuthorizationServer
class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

   @Override
   void configure(ClientDetailsServiceConfigurer clients) throws Exception {
      clients.inMemory()
         .withClient("my-client-with-secret")...
   }

}

Example token contents

JWT Bearer Tokens

OAuth2 and the Microservice

Spring Cloud Security

A further level of abstraction to make common microservice security use cases really easy to implement

Simple SSO Client

@EnableOAuth2Sso
@Controller
class Demo {
}
$ spring jar app.jar app.groovy
$ cf push -p app.jar

(That's it.)

How Does that Work?

Answer: configuration conventions. The app was bound to a service

$ cf bind-service app sso

and the service provides credentials.

To create the same bindings manually (e.g. in application.yml):

oauth2:
  client:
    tokenUri: https://login.run.pivotal.io/oauth/token
    authorizationUri: https://login.run.pivotal.io/oauth/authorize
    clientId: acme
    clientSecret: ${CLIENT_SECRET}
  resource:
    tokenInfoUri: http://uaa.run.pivotal.io/check_token
    id: openid
    serviceId: ${PREFIX:}resource

Resource Server with Spring Cloud

@EnableOAuth2Resource
@EnableEurekaClient
@RestController
class Demo {
  @RequestMapping("/")
  def home() { [id: UUID.randomUUID().toString(), content: "Hello Remote"] }
}

How does it work? Same as @EnableOAuth2Sso (bind to service providing credentials for conventional external configuration).

Single Page Apps

With backend services CORS restrictions make reverse proxy useful (@EnableZuulProxy). Then you can acquire tokens in the client app and relay them to back end.

With no backend services, don't be shy, use the session (authorization code flow is vastly superior).

Spring Session helps a lot too.

Relaying User Tokens

Front end app sends SSO token with user credentials to authenticate back end requests, back ends just relay it to each other as necessary.

Simple but possibly flawed: the front end only needs access to user details to authenticate, but you need to give it permission to do other things to allow it access to the back ends.

Idea: exchange (with full authentication) the incoming token for an outgoing one with different permissions (client but not scope). Can use password grant (e.g. with the incoming token as a password).

Token Relay with Spring Cloud

@EnableOAuth2Sso
@EnableZuulProxy
@Controller
class Demo {
}

Other Options

In Conclusion

#