Since the rise of the digital era, most enterprises keep their data in a digital format. But if their sensitive data lacks security, it can cause the data to be unreliable, unstable and unavailable to their business. We have to be prepared if an attacker breaches into our network and tries to hack our sensitive data. Whether it is in motion or at rest, encrypting our data and using the proper protection mechanisms will make it worthless for the hacker to use.
- Securing your cloud-native microservice architechture in Spring: Part 1
- Cryptographic Algorithms
- Key Mechanics
- Cloud-hosted Key management service
- Spring Cloud Config Server
When implementing our application, every programming language will provide us with a set of known libraries for cryptographic algorithms. A big flaw is implementing an algorithm by yourself, the known algorithms have been reviewed, patched and been known for their excellent security. These are the most used types that you can use for encryption at rest:
The key used in encrypting data at rest is used for both encrypting and decrypting the data. This key becomes very vulnerable if anyone gets a hold on it.
- Well known: Advanced Encryption Standard encryption
In asymmetric encryption, a pair of keys are used. A public key that is exposed and encrypts your data and a private key that is only known by the owner that decrypts your data. This key-pair can also be used to sign your data, so the application knows that it can trust the source of the data.
- Well known: Rivest–Shamir–Adleman encryption
Encryption keys are another aspect of encryption, handling the keys becomes just as sensitive as the data itself. That’s why we need mechanisms on how keys are stored and shared so attackers can’t get a hold on them.
Encryption key rotation will provide protection especially when the certificate expires, is corrupted or the key management admin is no longer part of the company. Lets say, you got a good eye at detecting patterns and detect that the same key is being used for encrypting data. To avoid this, you rotate your keys, and every time the same data field is encrypted it will result in a different encrypted message.
JSON Web Key (Set)
We discussed in the previous post about retrieving a JWK(S) to verify our JSON Web Token in our microservice. A JWK is a JSON object that represents a cryptographic key that consists of information to verify a JWT. If you like to dive into signing JSON documents you can check out this blog post on Digitally signing your JSON documents.
alg: is the algorithm for the key
kty: is the key type
use: is how the key was meant to be used. For the example above sig represents signature.
x5c: is the x.509 certificate chain
e: is the exponent for a standard pem
n: is the modulus for a standard pem
kid: is the unique identifier for the key
x5t: is the thumbprint of the x.509 cert (SHA-1 thumbprint)
Cloud-hosted Key management service
KMS is a fully managed service that allows you to manage your encryption keys in the cloud. Most of these KMSs offer the best way for encryption and generate, rotate and destroy your keys. But the KMS is vendor lock-in so all your keys will stay on the platform. To avoid vendor lock-in, we can implement our own open source version for managing our encryption keys.
A few examples to get an idea of KMS:
A few examples of open-source variants:
Spring Cloud Config Server
The Spring Cloud Config Server provides a centralized external configuration management backed optionally by a Git repository or database. Using a REST API for external configuration, Config Server supports encryption and decryption of properties and yml files. First step is downloading the Java Cryptography Extension on our local pc.
JCE provides a framework and implementation for encryption, key generation, key agreement and message authentication code algorithms. You’re not installing JCE itself, because it’s packaged within the Java SE binary. However, you do need to update its policy files from time to time. Downloads are available for Java 6, 7 and 8. This will allow the config server to use the encryption tool of the JCE.
After the download, the next step will be securing the config server by adding Spring Security to the classpath and configuring your Basic/OAuth2 authentication.
The config server supports encryption and decryption with a symmetric key or an asymmetric key-pair.
The choice of which key you will need is within your security terms.
The symmetric key is the easiest way to set up but less secure than the asymmetric one.
To set up a symmetric key, you just assign a string to the key holder:
To configure these asymmetric keys, we will need a keystore created by the keytool utility from the JDK. The public key will encrypt and the private key will decrypt your data.
To create a keystore you can do something like this in your command line:
This will generate a keystore for the config server to use. Place it in your repository project and configure it in your yml.
Example yml in the config server:
To encrypt the data, start up your config server locally and enter this in your command line.
When the encryption is done, we get an encrypted piece of data in your configuration in the form of:
What to store where?
When designing your config server, you have different options on where and to which our config server has access.
Using a Git repository
The default and most common way most of us use is via private Git repositories where we store our sensitive data where the config server can fetch it. Be aware, never put configuration inside your code repository, it violates the twelve-factor app which requires strict separation of config from code. Config varies substantially across deploys, code does not.
You can enable the health check to the config server within the application.
If you do this, always look at which version control would be the best fit, always check when they go into maintenance.
It could be that they host it in another timezone, which could lead to a cascading failure.
In my opinion, you can just disable the health checks with
spring.cloud.config.server.health.enabled=false and avoid further failures.
If you expect that the config server might go down temporarily when your client app starts, please provide a retry mechanism after a failure.
To enable a retry, first add
spring-retry to your classpath with
@EnableRetry annotation and
New to this list is the support for JDBC. This enables us to store configuration properties inside a relational database.
By switching the active spring profile to
JDBC and adding the dependency of
spring-jdbc to your classpath, Spring Boot will configure the datasource you included on the classpath.
To store the data you will need to set up new tables in your database.
For more information: using JDBC
HashiCorp’s Vault provides a centralized external management server.
Vault can manage static and dynamic secrets such as username/password for remote applications/resources and provide credentials for external services such as MySQL, PostgreSQL, Apache Cassandra, MongoDB, Consul, AWS and more.
Spring supports using the Vault as a backend for Spring Cloud Config.
If you are using Spring Boot, a quick way to enable Vault is to set your spring profile to
Spring Boot’s conditionals will activate all the auto configuration for a connection with the Vault server.
Using File System
So when you’re working locally on your machine, you can always look at the
native profile to activate the file system as your “backend”.
But I don’t recommend it for use in a deployment environment since it comes with various problems and extra setup.
One of those problems would be high availability, unlike Eureka, the config server doesn’t have the concept of peers.
The obvious option is to use a shared file system but it requires extra setup.
With the latest technologies coming up, you can expect that our data will be stored in an immutable ledger that is secured by cryptography. But we have to be aware of the arrival of quantum computers. This could make the best encryption algorithms useless. But as always, we will find a way to protect ourselves…