How to securely install apps on Debian based Linux distros

Reading Time: 7 minutes

Every newcomer (me included) after painstakingly (at least in the early days) installed the Linux operating system, had only one question in mind: OK, now what?!

Well now, it is time to install some apps!

For this blog I will be using the Pop!_Os which is a free and open source operating system based on Ubuntu (which itself is a variant of Debian).

In newer versions of Linux distros, there are a lot of GUI tools for installing new applications. For example the Pop!_Os uses a so-called Pop!_Shop and Ubuntu uses Ubuntu Software Center, from which you can install applications with a single click, LITERALLY! Those GUI tools use the distribution’s repositories so anything you install from there should be safe. If we need some app that is not included there what do we do? Well, the first thing we would think is, to do a little search using the apt tool. And that is also safe, for now. But what if our beloved app is not included in the preconfigured repositories? Then the only option left is to install it from external sources. Because time is passing by and impatience starts to nest, we can get tempted to copy-paste the first piped command which appears on google search. Well, that is where the trouble starts.


Try to understand commands you find online before executing them

In blogs and forums sometimes people can mistype a command (I do this often :)). Sometimes the command can work well on some distributions and not on others or it can be devastating. If you are not sure about a certain command you can always check the manual for the command or just read the distribution wiki page.

$ man tee

example of manual for the tee command

A curious case is when websites tell us to “pipewget or curl into bash in order to install their app. Sometimes they even tell us to ignore certificates as well.

$ wget -O – | sudo sh


example of “piping” wget into bash without using https

Imagine that the .sh file we are “piping” has a line in it similar to this one:

rm -rf /$TMP_DIR

What would happen if the connection closes midstream and all left from the script we are downloading is this:

rm -rf /

If that script gets executed, and it will because it is a perfectly legal script, it’s going to hurt badly. That is why some maintainers started wrapping code snippets into shell functions:

docleanup() { 
  rm -rf /$TMP_DIR


A script like this, if it is missing some part, will result in an error when executed. The latest versions of Linux should have a safeguard against rm -rf / but either way, check the script before executing or don’t “pipe” into bash.

Install apps from sources you trust

If you need some famous apps like IntelliJ or slack, go to their website and you will find all the information on how to install them. Lately, it is not unusual for software maintainers to provide a .deb file. When there is no other option and if you trust the source go for it, otherwise prefer to install the apps the old fashion way by downloading a .tar.gz file which you can extract wherever you want and later it will be easier to remove completely.

Another thing Linux users usually do is install extensions. I on the other hand like the original look and feel of most Linux distributions so I rarely visit those kinds of websites. By installing extensions from unofficial sources, you can become a victim of the second biggest virus to hit 2019 Linux users specifically running gnome-desktop environments, called the “Evil GNOME”. Rightly dubbed because it runs as an extension in (you guessed it) the gnome-desktop environment. And yes, the Linux world is not virus-free, because every software made by man can be broken by man. This virus can monitor your audio, keep track of newly created files, and even has a key-logger. If you need gnome extensions you at least should visit the official website for this.

If you use browser extensions check if they are on the browser recommended list, or are located in the GitHub repository, in which case you can check them out yourself. Some browser extensions can keep track of your browsing history and even the things you type if they have the required rights. The bottom point is to install extensions from the official and trusted websites or don’t install them at all.

Don’t use apt-key anymore

Some websites offer us their GPG key and repository in order to install and update their software, which will look something like:

$ wget -qO – https://<>/<repo-key-pub>.gpg | sudo apt-key add –

$ echo “deb https://<>/ <apt/stable/>” | sudo tee /etc/apt/sources.list.d/<my-repository>.list

$ sudo apt-get update

$ sudo apt-get install <my-package>

<repo-key-pub> will be replaced with their public key
<> will be replaced with their website or download path
<apt/stable/> will be replaced with their repository path
<my-repository> will be replaced with their repository name
<my-package> will be replaced with their package name, can be similar to the repository name

But when we try to execute this command on newer Debian-based distributions we will likely see the following output: “Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8))”. This message doesn’t mean that the developer decided he has better things to do and closed the project, but it has something to do with security.

The reason for this change is that when adding an OpenPGP key to /etc/apt/trusted.gpg or /etc/apt/trusted.gpg.d, the key is trusted by apt. But that is not all! That key is trusted by apt for all other repositories configured on the system that doesn’t have a signed-by option (we will see later in this blog), even the official Debian / Ubuntu repositories. As a result, any unofficial apt repository, which has its key in one of those 2 locations we mentioned, can replace any package on the system. Well, that is hardly likely that a source you trust will do that, but even they can get hacked. It’s also important to know, while the apt deprecation message says to “manage keyring files in trusted.gpg.d instead“, the Debian wiki states otherwise. That is because adding keys to /etc/apt/trusted.gpg and /etc/apt/trusted.gpg.d is equally insecure as we mentioned above.

Only 2 steps are required for the correct (secure) procedure:

STEP 1: Download the key into /usr/share/keyrings directory.

$ wget -O- https://<>/<repo-key-pub>.gpg | gpg –dearmor | sudo tee /usr/share/keyrings/<myrepository>-archive-keyring.gpg

gpg –dearmor is piped if the file is ASCII armored (encoded)
you would probably need to replace all text within <>
note that the key extension can be .gpg, .asc, .key, and probably others

There is nothing special to this location, it is just a directory. Convention states that directory /usr is for all the programs and support files used by regular users, /usr/share contains shared data among programs, and /usr/share/keyrings is just a descriptive name.

STEP 2: add the repository sources.list entry. Previously, a sources.list file from the /etc/apt/sources.list.d directory would look like this (just a simple file with the following content, nothing special):

deb stable main

However, to be able to use the key added under step 1, the sources.list entry must now look like this (/etc/apt/sources.list.d/<myrepository.list>):

deb [signed-by=/usr/share/keyrings/<myrepository>-archive-keyring.gpg] < stable main>

As you can see there is an additional signed-by option (as we mentioned somewhere above) which points to the exact location of the key. And we are almost done.

After this step you can update the package list and install your app:

$ sudo apt update & sudo apt install <my-package> -y


Spring Boot password encryption with Jasypt

Reading Time: 5 minutes

Securing sensitive data is extremely important. In the following tutorial, we will go through the process of encrypting sensitive data in a Spring Boot application. We will take an easy approach to this very common procedure which takes place in any software project. This will be easy in the context of setup and usage of the given high-security java library. Without the need for deep knowledge/in-depth understanding of cryptography, encryption capabilities and encryption algorithms. Just following a simple setup with a few configuration steps. It is recommended to rely on the secure default configuration, but also Jasypt offers quite some customization if one needs it.

Jasypt (Java Simplified Encryption) provides utilities for encrypting user sensitive information, such as DB passwords, servers’ credentials, or other sensitive personal data. This information is key to users privacy, so we as developers need to make sure that no one gets the right to access them, irrelevant of the place where they are stored, they always need to be encrypted. Never store sensitive data in plain mode. It’s common sense we need to follow and it’s also something we need to honour if we want to gain our user’s trust. For this tutorial, we will use a specific library, Jasypt Spring Boot Starter, widely used across the Spring Boot community.

Jasypt setup steps

  1. Add jasypt-spring-boot-starter maven dependency in the pom.xml of the Spring Boot project
  2. Select a secret key to be used for encryption and decryption
  3. Generate Encrypted Key
  4. Add the Encrypted key in the config file
  5. Run the application

Let’s go into details in all of these steps:

Step 1. Adding maven dependency


This comes as a regular entry in the pom.xml file list of dependencies.

We should try to use latest stable versions. This version is the latest one at this moment and it offers better support for newer versions of Spring Boot. starting from 2.1.x and upwards. Also would advise using this because it comes with a more secure encryption algorithm by default, “PBEWITHHMACSHA512ANDAES_256”.

Step 2. Select a secret key to be used for encryption and decryption

This secret key will be used to encrypt and descript the data. You can think of it as a safeguard to further improve security. What it does, it actually adds a random string to the beginning or end of the input text prior to hashing or encrypting the value. This secret key goes in the property file, application.yml/ in the Spring Boot project itself.

           password: salting

Step 3. Generate Encrypted Key

Jasypt supplies a lot of (CLI) tools. In order to use these tools, you should download the distribution zip file (named jasypt-$ and unzip it. There will be an appropriate .bat or .sh file for the needed operation digest/encrypt/decrypt.

Example for encryption

$ ./ input="This is my message to be encrypted" password=MYPASSWORD

Example for decryption

$ ./ input="8fsdfdsafdsa9ffsad0fdsa0fdsfdsa3231x" password=MYPASSWORD

Another way of using Jasypt for encrypting your data is by using some online tools that provide Jasypt operations.

The simplest and most convenient way is a maven plugin. Not only that you can use it for a single value, it offers the capabilities to encrypt all sensitive data with a single command, meaning all placeholders will be updated in one step.


This jasypt-maven-plugin, by default, will check for configuration files under ./src/main/resources, or the regular Spring Boot resource folders. But also, Environment variables can be used to supply this master password. Instead of exposing the password “salting” inside the project itself, an Environment Variable can be created with, for instance, ENCRYPTION_MASTER_PASSWORD and then in the config file, password: ${ENCRYPTION_MASTER_PASSWORD}.

Example for encrypting a single value from a terminal.

This example uses the encryption password as an argument. Important, the terminal session needs to be opened where the pom.xml file with the maven plugin is located.

mvn jasypt:encrypt-value -Djasypt.encryptor.password=salting -Djasypt.plugin.value="secureDataWeNeedToEncrypt"

Example for encrypting all strings within projects property file.

The last argument is optional since Jasypt will scan that location anyway. What is important is that sensitive placeholders in the application property file MUST be wrapped in DEC() parenthesis. Activedirectory:password: DEC(supersecret) OracleDB:password: DEC(alsosupersecret).

mvn jasypt:encrypt -Djasypt.encryptor.password=salting -Djasypt.plugin.path="file:src/main/resources/application.yml"

If the previous statement completed successfully then, all sensitive data should be updated with their encrypted value. Updated properties output should be something like, Activedirectory:password: ENC(sFJDfdsfjjA8saT7YC65bsf71d0) OracleDB:password: ENC(34jjfsdfds+fds/fsd7Hs)

Step 4. Add the encrypted key in the config file

If you have been using the latest approach, then the files have already been updated with the newly encrypted values. All sensitive data wrapped with a DEC() is now encrypted, and all other strings in the configuration remained unchanged. If some of the other approaches were chosen, going one placeholder at a time, or using the cli, then we need to update the configuration file entries one by one. Still, the properties need to be wrapped in ENC() parenthesis anyway, since the output of the cli is only the encrypted value.

For the reverse process, it’s vice-versa, the first argument of the statement is: decrypt and all placeholders must be wrapped in ENC() parenthesis before execution.

Step 5. Run the application

That’s it. Your Spring Boot project will automatically decrypt all sensitive data when you start the application, no additional configuration is needed. Let me know in the comments section how was your experience. Was it smooth or are there some ongoing issues?

Securing your microservices with OAuth 2.0. Building Authorization and Resource server

Reading Time: 8 minutes

We live in a world of microservices. They give us an easy opportunity to scale our application. But as we scale our application it becomes more and more vulnerable. We need to think of a way of how to protect our services and how to keep the wrong people from accessing protected resources. One way to do that is by enabling user authorization and authentication. With authorization and authentication, we need a way to manage credentials, check the access of the requester and make sure people are doing what they suppose to.

When we speak about Spring (Cloud) Security, we are talking about Service authorization powered by OAuth 2.0. This is how it exactly works:


The actors in this OAuth 2.0 scenario that we are going to discuss are:

  • Resource Owner – Entity that grants access to a resource, usually you!
  • Resource Server – Server hosting the protected resource
  • Client – App making protected resource requests on behalf of a resource owner
  • Authorization server – server issuing access tokens to clients

The client will ask the resource owner to authorize itself. When the resource owner will provide an authorization grant with the client will send the request to the authorization server. The authorization server replies by sending an access token to the client. Now that the client has access token it will put it in the header and ask the resource server for the protected resource. And finally, the client will get the protected data.

Now that everything is clear about how the general OAuth 2.0 flow is working, let’s get our hands dirty and start writing our resource and authorization server!

Building OAuth2.0 Authorization server

Let’s start by creating our authorization server using the Spring Initializr. Create a project with the following configuration:

  • Project: Maven Project
  • Artefact: auth-server
  • Dependencies: Spring Web, Cloud Security, Cloud OAuth2

Download the project, copy it into your workspace and open it via your IDE. Go to your main class and add the @EnableAuthorizationServer annotation.

public class AuthServerApplication {

    public static void main(String[] args) {, args);


Go to the file and make the following modification:

  • Change the server port to 8083
  • Set the context path to be “/api/auth”
  • Set the client id to “north47”
  • Set the client secret to “north47secret”
  • Enable all authorized grant types
  • Set the client scope to read and write



The client id is a public identifier for applications. The way that we used it is not a good practice for the production environment. It is usually a 32-character hex string so it won’t be so easy guessable.

Let’s add some users into our application. We are going to use in-memory users and we will achieve that by creating a new class ServiceConfig. Create a package called “config” with the following path: com.north47.authserver.config and in there create the above-mentioned class:

public class ServiceConfig extends GlobalAuthenticationConfigurerAdapter {

    public void init(AuthenticationManagerBuilder auth) throws Exception {

    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();

With this we are defining one user with username: ‘filip’ and password: ‘1234’ with a role ADMIN. We are defining that BCryptPasswordEncoder bean so we can encode our password.

In order to authenticate the users that will arrive from another service we are going to add another class called UserResource into the newly created package resource (com.north47.autserver.resource):

public class UserResource {

    public Principal user(Principal user) {
        return user;

When the users from other services will try to send a token for validation the user will also be validated with this method.

And that’s it! Now we have our authorization server! The authorization server is providing some default endpoints which we are going to see when we will be testing the resource server.

Building Resource Server

Now let’s build our resource server where we are going to keep our secure data. We will do that with the help of the Spring Initializr. Create a project with the following configuration:

  • Project: Maven Project
  • Artefact: resource-server
  • Dependencies: Spring Web, Cloud Security, Cloud OAuth2

Download the project and copy it in your workspace. First, we are going to create our entity called Train. Create a new package called domain into com.north47.resourceserver and create the class there.

public class Train {

    private int trainId;
    private boolean express;
    private int numOfSeats;

    public Train(int trainId, boolean express, int numOfSeats) {
        this.trainId = trainId; = express;
        this.numOfSeats = numOfSeats;

   public int getTrainId() {
        return trainId;

    public void setTrainId(int trainId) {
        this.trainId = trainId;

    public boolean isExpress() {
        return express;

    public void setExpress(boolean express) { = express;

    public int getNumOfSeats() {
        return numOfSeats;

    public void setNumOfSeats(int numOfSeats) {
        this.numOfSeats = numOfSeats;


Let’s create one resource that will expose an endpoint from where we can get the protected data. Create a new package called resource and there create a class TrainResource. We will have one method only that will expose an endpoint behind we can get the protected data.

public class TrainResource {

    public List<Train> getTrainData() {

        return Arrays.asList(new Train(1, true, 100),
                new Train(2, false, 80),
                new Train(3, true, 90));

Let’s start the application and send a GET request to http://localhost:8082/api/services/train. You will be asked to enter a username and password. The username is user and the password you can see from the console where the application was started. By entering this credentials will give the protected data.

Let’s change the application now to be a resource server by going to the main class ResourceServerApplication and adding the annotation @EnableResourceServer.

public class ResourceServerApplication {

    public static void main(String[] args) {, args);


Go to the application properties file and do the following changes:


What we have done here is:

  • Changed our server port to 8082
  • Set context path: /api/services
  • Gave user info URI where the user will be validated when he will try to pass a token

Now if you try to get the protected data by sending a GET request to http://localhost:8082/api/services/train the server will return to you a message that you are unauthorized and that full authentication is required. That means that without a token you won’t be able to access the resource.

So that means that we need a fresh new token in order to get the data. We will ask the authorization server to give us a token for the user that we previously created. Our client in this scenario will be the postman. The authorization server that we previously created is exposing some endpoints out of the box. To ask the authorization server for a fresh new token send a POST request to the following URL: localhost:8083/api/auth/oauth/token.

As it was said previously that postman in this scenario is the client that is accessing the resource, it will need to send the client credentials to the authorization server. Those are the client id and the client secret. Go to the authorization tab and add as a username the client id (north47) and the password will be the client secret (north47secret). On the picture below is presented how to set the request:

What is left is to say the username and password of the user. Open the body tab and select x-www-form-urlencoded and add the following values:

  • key: ‘grant_type’, value: ‘password’
  • key: ‘ client_id’, value: ‘north47’
  • key: ‘ username’, value: ‘filip’
  • key: ‘password’, value ‘1234’

Press send and you will get a response with the access_token:

    "access_token": "ae27c519-b3da-4da8-bacd-2ffc98450b18",
    "token_type": "bearer",
    "refresh_token": "d97c9d2d-31e7-456d-baa2-c2526fc71a5a",
    "expires_in": 43199,
    "scope": "read write"

Now that we have the access token we can call our protected resource by inserting the token into the header of the request. Open postman again and send a GET request to localhost:8082/api/services/train. Open the header tab and here is the place where we will insert the access token. For a key add “Authorization” and for value add “Bearer ae27c519-b3da-4da8-bacd-2ffc98450b18”.


And there it is! You have authorized itself and got a new token which allowed you to get the protected data.

You can find the projects in our repository:

And that’s it! Hope you enjoyed it!