securing microservices using play and akka http
TRANSCRIPT
Securing Microservices
using Play and Akka HTTPRafal Gancarz
@RafalGancarz
1
About me• Lead Consultant at
OpenCredo
• Helping companies transform their IT platforms and the ways their do business
• Technologist, architect, developer
• Agile practitioner & evangelist
• Scala <- Java <- PHP
2
(Micro)services• SOA reloaded
• Lightweight, open standards
• Loosely coupled, self-contained
• Independent and scalable
• Bounded context (part of business domain)
3
Securing the monolith
DB
authentication
Pros• single entry point • limited attack surface • centralised authentication &
authorisation Cons• totally exposed when
compromised
4
Securing the monolith - considerations
• Combined presentation and business logic tier
• End user login
• Session based authentication
• Single sign-on (usually with SAML)
5
Securing microservices (first take)
DB
Pros• siloed data Cons• large attack surface • multiple auth enforcement
points • shared auth data storeDB DB
6
• Who is the consumer (the end user vs the third-party system)?
• Is user context relevant?
• access control granularity
• act on behalf
• What are the security related requirements?
• highly sensitive data
• integration over public internet
• social login
• single sign-on (SSO)
Securing microservices - considerations
7
• What are commercial requirements for your project?
• time to market
• availability of skills / expertise
• buy vs build
• What about the legacy?
• existing security implementation
• interoperability with the legacy platform
Securing microservices - considerations
8
API gateway
DB DB DB
API gateway
Pros• single point of entry • limited surface attack • configurable authentication
protocols and backends • faster time to market • gateway availability/scalability Cons• additional cost • services unsecured internally • HTTP level access control • limited auth context
9
HTTP basic auth + client id&secret
DB DB DB
Pros• easy • good for third-party integration • stateless Cons• requires TLS • doesn’t expire • difficult to enforce at scale
(unless used with API gateway)
client_id client_secret
10
Play Framework• Basic HTTP auth with HTTP filter
• Basic HTTP auth with Action builder
• Play2.x Authentication and Authorization module (https://github.com/t2v/play2-auth)
• Pac4j module (https://github.com/leleuj/play-pac4j)
• Secure Social module (http://securesocial.ws/)
• Silhouette module (http://silhouette.mohiva.com/)
11
Akka HTTP• authenticateBasicX directives
• http://doc.akka.io/docs/akka-stream-and-http-experimental/2.0-M2/scala/http/routing-dsl/directives/security-directives/authenticateBasic.html#authenticatebasic
def myUserPassAuthenticator(credentials: Credentials): Future[Option[String]] = credentials match { case p @ Credentials.Provided(id) => Future { // potentially if (p.verify("s3cr3t")) Some(id) else None } case _ => Future.successful(None) } val route = Route.seal { path("secured") { authenticateBasicAsync(realm = "secure site", myUserPassAuthenticator) { userName => complete(s"The user is '$userName'") } } }
12
OAuth2+OpenID Connect
DB DB DB
Auth Server
Pros• standard based • popular for social login & delegated
authorisation • caters for browser, mobile and
server-to-server use cases • token expiry Cons• requires TLS • requires Authorisation Server • developed initially as authorisation
framework • numerous flavours used • non-trivial to get right • authentication impl out of scope
13
Play Framework
• Pac4j module (https://github.com/leleuj/play-pac4j) - supports OAuth2, OAuth2 and OpenID
• Secure Social module (http://securesocial.ws/) - supports OAuth1 and OAuth2
• Silhouette module (http://silhouette.mohiva.com/) - supports OAuth1, OAuth2 and OpenID
14
Akka HTTP• authenticateOAuth2X directives• http://doc.akka.io/docs/akka-stream-and-http-experimental/2.0-M2/scala/http/
routing-dsl/directives/security-directives/authenticateOAuth2.html#authenticateoauth2
def authenticateOAuth2[T](realm: String, authenticator: Authenticator[T]): AuthenticationDirective[T]
Usage the same as HTTP basic but requires validating access token retrieved from the header (not supported natively).
15
OpenID Connect• Nimbus (https://bitbucket.org/connect2id/
oauth-2.0-sdk-with-openid-connect-extensions)
• Apache Oltu (https://oltu.apache.org/)
https://openid.net/developers/specs/ 16
JSON Web Token
DB DB DB
Auth Server
Pros• auth claims can be signed
(HMAC or RSA) • compact (suitable for URLs,
headers, query params) • self-contained, stateless • excellent SAML alternative for
SSO Cons• requires TLS or encryption • authentication impl out of scope
http://jwt.io/17
JSON Web Token• No built-in support in Play or Akka HTTP
• authentikat-jwt (https://github.com/jasongoodwin/authentikat-jwt) - Scala
• iain-logan/jwt (https://github.com/iain-logan/jwt) - Scala
• jose4j (https://bitbucket.org/b_c/jose4j/wiki/Home) - Java
• jjwt (https://github.com/jwtk/jjwt) - Java
18
Mutually authenticated TLS
DB DB DB
Pros• strong point to point security Cons• requires PKI • key management and
distribution challenging • difficult to implement and
troubleshoot • no user context
mTLS
19
Play Framework - server-side• https://www.playframework.com/documentation/2.4.x/ConfiguringHttps
class CustomSSLEngineProvider(appProvider: ApplicationProvider) extends SSLEngineProvider {
def createSSLContext(applicationProvider: ApplicationProvider): SSLContext = { val keyManagers = readKeyManagers() val trustManagers = readTrustManagers() val sslContext = SSLContext.getInstance("TLS") sslContext.init(keyManagers, trustManagers, null) sslContext}
override def createSSLEngine(): SSLEngine = { val sslContext = createSSLContext(appProvider) val sslParameters = sslContext.getDefaultSSLParameters sslParameters.setUseCipherSuitesOrder(true) sslParameters.setNeedClientAuth(true) val engine = sslContext.createSSLEngineengine.setSSLParameters(sslParameters) engine
} }
20
Akka HTTP - server-side• http://doc.akka.io/docs/akka-stream-and-http-experimental/2.0-M2/scala/http/low-level-server-side-api.html#serversidehttps
def createSSLContext(): SSLContext = { val keyManagers = readKeyManagers() val trustManagers = readTrustManagers() val sslContext = SSLContext.getInstance("TLS") sslContext.init(keyManagers, trustManagers, null) sslContext} def run() = { implicit val system = ActorSystem("server") implicit val materializer = ActorMaterializer() val sslContext = createSSLContext() val serverSource = Http().bind(interface = "localhost", port = 8200, ServerSettings(system), Some(HttpsContext(sslContext, Some(immutable.Seq("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")), Some(immutable.Seq("TLSv1.2")), Some(Need), Some(sslContext.getDefaultSSLParameters)))) … }
21
Authorisation
• At the perimeter or within the business logic?
• Where user roles/permissions are coming from (each bounded context might have different access control considerations)?
• How is the user context passed into the service?
22
Play Framework
• Authorisation with HTTP filter
• Authorisation with Action builder
• Deadbolt (http://deadbolt.ws/#/home) - works with Silhouette and SecureSocial for authentication
23
Akka HTTP• authorize directive
• http://doc.akka.io/docs/akka-stream-and-http-experimental/2.0-M2/scala/http/routing-dsl/directives/security-directives/authorize.html#authorize
case class User(name: String)
val admins = Set("Peter") def hasAdminPermissions(user: User): Boolean = admins.contains(user.name) val route = Route.seal { authenticateBasic(realm = "secure site", myUserPassAuthenticator) { user => path("peters-lair") { authorize(hasAdminPermissions(user)) { complete(s"'${user.name}' visited Peter's lair") } } } }
24
Key takeaways• Securing microservice based architectures is
challenging
• The technology landscape changes all the time
• One size (solution) doesn’t fit all
• Consider your requirements before committing to a technical solution
25
Questions?• Email: [email protected]
• Twitter: @RafalGancarz
• See me tomorrow at lunchtime for a Q&A session on Securing Microservices using Play and Akka HTTP
• Visit OpenCredo’s booth tomorrow and enter a draw to win Apple Watch!
• See you at the Scala Exchange party later :)
• Thank you!
26