Software Development

Microservices for Java Developers: Managing Security and Secrets

1. Introduction

Security is an exceptionally important element of the modern
software systems. It is a huge topic by itself which includes a lot of
different aspects and should never come as an afterthought. It is hard to get
everything right, particularly in the context of the distributed microservice architecture,
nonetheless along this part of the tutorial we are going to discuss the most critical
areas and suggest on how you may approach them.

If you have the security expert in your team or organization, this is a great start of the journey. If not, you should better hire one, since the developer’s expertise may vary greatly here. No matter what please restrain from rolling out your own security schemes.

And at last, before we get started, please make the Secure Coding Guidelines for Java SE a mandatory reading for any Java developer in your team. Additionally, Java SE platform official documentation includes a good summary of all the specifications, guides and APIs related to Java security.

2. Down to the Wire

In any distributed system a lot of data travels between
different components. Projecting that to the microservice architecture,
each service either directly communicates with other services or passes the
messages or/and events around.

Using the secure transport is probably the most fundamental way
to protect data in the transit from being intercepted or tampered. For web-based
communication, it typically means the usage of HTTPS (or better to say, HTTP over SSL / TLS) to shelter
privacy and preserve data integrity.
Interestingly, although for HTTP/2
the presence of the secure transport is still optional, it is mostly
exclusively used with SSL / TLS.

Beside just HTTPS,
there are many other protocols which rely on TLS for
securing the communication, like for example DTLS,
SFTP, WSS
and SMTPS, to name a few. It
is also worth mentioning Message
Security Layer
, an extensible and
flexible secure messaging framework which was open-sourced by Netflix.

3. Security in Browser

On the web browser side, a lot of the efforts are invested in making the web sites more secure by supporting mechanisms like HTTP Strict Transport Security (HSTS), HTTP Public Key Pinning (HPKP), Content Security Policy (CSP), secure cookies and same-site cookies (the JCG Car Rentals customer and administration web portals would certainly rely on some of those).

On the scripting side we have Web Cryptography API specification which describes a JavaScript API for performing basic cryptographic operations in the web applications (hashing, signature generation and verification, and encryption and decryption).

4. Authentication and Authorization

Identifying all kinds of possible participants (users, services, partners, and external systems) and what they are allowed to do in the system is yet another aspect of securing your microservices. It is closely related to two distinct processes, authentication and authorization.

Authentication
is the process to ensure that the entity is who or what it claims to be.
Whereas the authorization
is the process of specifying and imposing the access rights, permissions and
privileges this particular entity has.

For the majority of the applications out there, the single-factor
authentication
(typically, based on providing the password) is still the
de-facto choice, despite its numerous weaknesses.
On the bright side, the different methods of multi-factor authentication
slowly but surely are getting more widespread adoption.

With respect to the authorization, there are
basically two prevailing models: role-based
access control
(also called RBAC) and access control lists
(ACLs). As we
are going to see later on, most of the security frameworks support both these
models so it is a matter of making the deliberate decision which one fits the
best to the context of your microservice architecture.

If we shift the authentication and authorization towards the
web applications and services, like with our JCG
Car Rentals
platform, we are most likely to end up with two industry
standards, OAuth 2.0 and OpenID Connect 1.0.

The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf. – https://tools.ietf.org/html/rfc6749

OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner – https://openid.net/connect/

Those two standards are closely related to the JSON Web Token (JWT) specification, which is
often used to serve as OAuth 2.0
bearer token
.

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. – https://tools.ietf.org/html/rfc7519

Amid numerous data breaches and leaks of the personal information (hello, Mariott), security becomes as important as never before. It is absolutely essential to familiarize, follow and stay up to date with the best security practices and recommendations. The two excellent guides on the subject, OAuth 2.0 Security Best Current Practices and JSON Web Token Best Current Practices, certainly fall into must-read category.

5. Identity Providers

Once the authentication and authorization decisions
are finalized, the next obvious question is should you implement everything
yourself or may be look around for existing solutions? To admit the truth, are
your requirements so unique that you have to waste engineering time and build
your own implementations? Is it in the core of your business? It is surprising
how many organizations fall into DIY mode and reinvent
the wheel over and over again.

For JCG Car Rentals platform
we are going to use Keycloak, the established open-source identity
and access management solution which fully supports OpenID Connect.

Keycloak is an open source Identity and Access Management solution aimed at modern applications and services. It makes it easy to secure applications and services with little to no code. – https://www.keycloak.org/about.htmlЕщ

The Keycloak comes
with quite comprehensive configuration
and installation guides
but it is worth to mention that we are going to use
it to manage the identity of the JCG Car
Rentals
customers and support staff.

Beside the Keycloak,
another notable open-source alternative to consider is WSO2 Identity Server,
which could have worked for JCG Car
Rentals
as well.

WSO2 Identity Server is an extensible, open source IAM solution to federate and manage identities across both enterprise and cloud environments including APIs, mobile, and Internet of Things devices, regardless of the standards on which they are based. – https://wso2.com/identity-and-access-management/features/

In you are looking to completely outsource the identity management of your microservices, there is a large number of certified OpenID providers and commercial offerings to choose from.

6. Securing Applications

The security on the applications and services side is
probably where the most efforts will be focused on. In the Java ecosystem there
are basically two foundational frameworks for managing authentication and authorization
mechanisms, Spring
Security
and Apache Shiro.

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications. – https://spring.io/projects/spring-security

Indeed, since our Reservation Service is built on top of the Spring Boot and Spring WebFlux, the choice in favor of Spring Security is obvious. It takes literally a few lines of configuration to have full-fledged OpenID Connect integrated into the service. The code snippet below illustrates just one of the possible ways to do that.

@EnableReactiveMethodSecurity
@EnableWebFluxSecurity
@Configuration
public class WebSecurityConfiguration {
    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    private String issuerUri;

    @Bean
    SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http){
        http
            .cors()
            .configurationSource(corsConfigurationSource())
            .and()
            .authorizeExchange()
            .pathMatchers(HttpMethod.OPTIONS).permitAll()
            .anyExchange()
            .authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt();
        return http.build();
    }

    @Bean
    ReactiveJwtDecoder jwtDecoder() {
        return ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
    }
}

The spring.security.oauth2.resourceserver.jwt.issuer-uri
points out to the JCG Car Rentals instance
of the Keycloak realm. In case when Spring Security is out of
scope, Apache Shiro is certainly worth
considering.

Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management… – https://shiro.apache.org/

A little bit less known is the pac4j
security engine also focused on protecting the web applications and web
services. The Admin Web Portal of the
JCG Car Rentals platform relies on pac4j to integrate with Keycloak using OpenID Connect.

Since OpenID Connect uses JWT (and related specifications) you may need to onboard one of the libraries which implements the specs in question. The most widely used ones include Nimbus JOSE+JWT, jose4j, Java JWT and Apache CXF.

If we expand our coverage beyond just Java to a broader JVM landscape, there are a few other libraries you may run into. One of them is Silhouette, used primarily by Play Framework web applications.

7. Keeping Secrets Safe

Most (if not all) of the services in typical microservice architecture would depend on some sort of configuration in order to function as intended. This configuration is usually specific to an environment the service is deployed into and, if you follow the 12 Factor App methodology, you already know that such configuration has to be externalized and separated from the code.

Still, many organizations store the configuration close by to the service, in the configuration files or even hardcoded in the code. What makes the matter worse is that often such configuration includes sensitive information, like for example credentials to access data stores, service accounts or encryption keys. Such pieces of data are classified as secrets and should never leak in plain. The projects like git-secrets would help you to prevent committing secrets and credentials into source control repositories.

Luckily, there are several options to look at. The simplest one is to use the encryption and store only the encrypted values. For Spring Boot applications, you may use Spring Boot CLI along with Spring Cloud CLI to encrypt and decrypt property values.

$ ./bin/spring encrypt --key <secret> <value>
d66bcc67c220c64b0b35559df9881a6dad8643ccdec9010806991d4250ecde60

Such encrypted values should be prefixed in the configuration with the special {cipher} prefix, like in this YAML fragment:

spring:   
  data:     
    cassandra:       
      password:"{cipher}d66bcc67c220c64b0b35559df9881a6dad8643ccdec9010806991d4250ecde60" 

To configure the symmetric key we just need to set encrypt.key
property or better, use ENCRYPT_KEY environment
variable. The Jasypt’s Spring Boot
integration
works in similar fashion by providing the encryption support
for property sources in Spring
Boot
applications.

Using encrypted properties works but is quite naïve, the arguably
better approach would be to utilize a dedicated secret management
infrastructure, like for example Vault
from HashiCorp.

Vault secures, stores, and tightly controls access to tokens, passwords, certificates, API keys, and other secrets in modern computing. – https://learn.hashicorp.com/vault/#getting-started

Vault makes secrets management secure and really easy. The services built on top of Spring Boot, like Reservation Service from JCG Car Rentals platform, may benefit from first-class Spring Cloud Vault integration.

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>

One of the very power features which Spring Cloud Vault  provides is the ability to plug Vault key/value store as the application property source. The Reservation Service leverages that using bootstrap.yml configuration file.

spring:
  application:
    name: reservation-service
  cloud:
    vault:
      host: localhost
      port: 8200
      scheme: https
      authentication: TOKEN
      token: <token>
      kv:
        enabled: true

Although Vault is probably the most known one, there are a number of decent alternatives which fit nicely into microservice architecture. One of the pioneers is Keywhiz, a system for managing and distributing secrets, which was developed and open-sourced by Square. Another one is Knox, the service for storing and rotating secrets, keys, and passwords used by other services, came out of Pinterest.


 

8. Taking Care of Your Data

Data is probably the most important asset you may ever have and as such, it should be managed with a great care. Some pieces of data like credit card numbers, social security numbers, bank accounts or/and personally identifiable information (PII) are very sensitive and should be operated securely. These days that typically assumes it has to be encrypted (which prevents data visibility in the case of unauthorized access or theft).

In the Keeping Secrets Safe section we have discussed the ways to manage encryption keys however you still have to decide if the data should be encrypted at application level or at storage level. Although both approaches have own pros and cons, not all data stores support encryption at rest, so you may not have a choice here. In this case, you may find invaluable Cryptographic Storage and Password Storage cheat sheets which OWASP Foundation publishes and keeps up to date with respect to the latest security practices.

9. Scan Your Dependencies

It is very likely that each microservice in your microservices ensemble depends on multiple frameworks or libraries, which in turn have own set of dependencies. Keeping your dependencies up to date is yet another aspect of security measures since the vulnerabilities may be discovered in any of those.

The OWASP dependency-check is an open source solution which can be used to scan the Java applications in order to identify the use of known vulnerable components. It has dedicated plugins for Apache Maven, Gradle, SBT and integrated into build definitions of each JCG Car Rentals service.

The OWASP dependency-check is an open source solution which can be used to scan the Java applications in order to identify the use of known vulnerable components. It has dedicated plugins for Apache Maven, Gradle, SBT and is integrated into build definitions of each JCG Car Rentals service. The following fragment in the Reservation Service‘s pom.xml illustrates the usage scenario.

<plugin>
	<groupId>org.owasp</groupId>
	<artifactId>dependency-check-maven</artifactId>
	<version>4.0.0</version>
	<executions>
		<execution>
			<goals>
				<goal>check</goal>
			</goals>
		</execution>
	</executions>
</plugin>

To give an idea what the OWASP dependency-check report prints out, let us take a look at some of the dependencies identified with known vulnerabilities in the Reservation Service.

Dependency CPE Coordinates Highest
Severity
CVE Count CPE Confidence Evidence Count
jul-to-slf4j-1.7.25.jar cpe:/a:slf4j:slf4j:1.7.25 org.slf4j:jul-to-slf4j:1.7.25 High 1 Highest 28
jcl-over-slf4j-1.7.25.jar cpe:/a:slf4j:slf4j:1.7.25 org.slf4j:jcl-over-slf4j:1.7.25 High 1 Highest 29
slf4j-api-1.7.25.jar cpe:/a:slf4j:slf4j:1.7.25 org.slf4j:slf4j-api:1.7.25 High 1 Highest 29

Since JCG Car Rentals has a couple of components which use Node.js, it is important to audit their package dependencies for security vulnerabilities as well. The recently introduced npm audit command scans each project for vulnerabilities and automatically installs any compatible updates to vulnerable dependencies. Below is an example of the audit command execution.

$ npm audit

                       === npm audit security report ===
found 0 vulnerabilities
 in 20104 scanned packages

10. Packaging

Ever since Docker brought the containers to the masses, they become the de-facto packaging and distribution model for all kind of applications, including the Java ones. But with the great power comes great responsibility: the vulnerabilities inside the container could make your applications severely exposed. Fortunately, we have Clair, vulnerability static analysis for containers.

Clair is an open source project for the static analysis of vulnerabilities in application containers (currently including appc and Docker). – https://github.com/coreos/clair

Please do not ignore the threats which may come from the containers and make the vulnerabilities scan a mandatory step before publishing any images.

Going further, let us talk about gVisor, the container runtime sandbox, which takes another perspective on security by fencing the containers at runtime.

gVisor is a user-space kernel, written in Go, that implements a substantial portion of the Linux system surface. It includes an Open Container Initiative (OCI) runtime called runsc that provides an isolation boundary between the application and the host kernel. – https://github.com/google/gvisor

This technology is quite new and certain limitations still
exists but it opens a whole new horizon for running the containers securely.

11. Watch Your Logs

It is astonishing how often the application or service logs become the security hole by leaking the sensitive or personally identifiable information (PII). The common approaches to address such issues are to use masking, filtering, sanitization and data anonymization.

This OWASP Logging Cheat Sheet is a focused document to provide the authoritative guidance on building application logging mechanisms, especially related to security logging.

12. Orchestration

Up to now we have been mostly concentrated on how to make the security measures an integral part of the applications and services, using dedicated libraries and frameworks. It is all good but over time you may see the same patterns reappearing over and over again. Won’t it be wonderful if we could offload such repeating cross-cutting concerns somewhere else? It makes a perfect sense and at some extent, it is already happening …

In case you orchestrate your microservices deployments using Apache Mesos or Kubernetes, there are quite a lot of the security-related features which you get for free. However, the most interesting developments are happening in the newborn infrastructure layer, called service meshes.

The most advanced, production-ready service meshes as of now include Istio, Linkerd and Consul Service Mesh. Although we are going to talk more about these things later in the tutorial, it is worth to mention that they take upon themselves a large set of concerns by following best security practices and conventions.

13. Sealed Cloud

So far we have talked about open-sourced solutions which are by and large agnostic to the hosting environment but if you are looking towards deploying your microservices in the cloud, it would make more sense to learn the managed options your cloud provider offers.

Let us take a quick look at what the leaders in the space have for you. Microsoft Azure includes Key Vault to encrypt keys and small secrets (like passwords) but the complete list of security-related services is quite comprehensive. It also has a security center, one-stop service for unified security management and advanced threat protection.

The list of security-related products which are offered by Google Cloud is impressive. Among many, there is also a dedicated service to manage encryption keys, Key Management Service (or shortly KMS) which, surprisingly, does not directly store secrets (it could only encrypt secrets that you should store elsewhere). The security portal is a great resource to learn your options.

AWS, the long-time leader in the space, has many security products to choose from. It even offers two distinct services to manage your encryption keys and secrets, Key Management Service (KMS) and Secrets Manager. Besides the managed offering, it is worth to mention the open-sourced Confidant from Lyft which stores secrets in DynamoDB using encryption at rest. This reference to the cloud security web page will help you to get started.

14. Conclusions

For most of us security is a difficult subject. And applying proper security boundaries and measures while implementing microservice architecture is even more difficult but absolutely necessary. In this part of the tutorial we have highlighted a set of key topics you may very likely run into but it is far from being exhaustive.

15. What’s next

In the next section of the tutorial we are going
to talk about various testing practices and techniques in the context of microservice architecture.

Andrey Redko

Andriy is a well-grounded software developer with more then 12 years of practical experience using Java/EE, C#/.NET, C++, Groovy, Ruby, functional programming (Scala), databases (MySQL, PostgreSQL, Oracle) and NoSQL solutions (MongoDB, Redis).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button