Sophia Parafina

Securing the AtSea App with Docker Secrets

Passing application configuration information as environmental variables was once considered best practice in 12 factor applications. However, this practice can expose information in logs, can be difficult to track how and when information is exposed, third party applications can access this information. Instead of environmental variables, Docker implements secrets to manage configuration and confidential information.

Secrets are a way to keep information such as passwords and credentials secure in a Docker CE or EE with swarm mode. Docker manages secrets and securely transmits it to only those nodes in the swarm that need access to it. Secrets are encrypted during transit and at rest in a Docker swarm. A secret is only accessible to those services which have been granted explicit access to it, and only while those service tasks are running.

The AtSea Shop is an example storefront application that can be deployed on different operating systems and can be customized to both your enterprise development and operational environments. The previous post showed how to use multi-stage builds to create small and efficient images. In this post, I’ll demonstrate how secrets are implemented in the application.

Creating Secrets

Secrets can be created using the command line or with a Compose file. The AtSea application uses nginx as a reverse proxy secured with HTTPS. To accomplish this, I created a self-signed x509 certificate.

mkdir certs
openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key -x509 -days 365 -out certs/domain.crt

I then created secrets using the domain key and certificate for nginx.

docker secret create revprox_cert certs/domain.crt
docker secret create revprox_key certs/domain.key

I also used secrets to hold the PostgreSQL database password and a token for the payment gateway by making files that contained the password and token. For example, the postgres_password file contains the password ‘gordonpass’. In the compose file, I added the secrets:

secrets:
 postgres_password:
 file: ./devsecrets/postgres_password
 payment_token:
 file: ./devsecrets/payment_token

 I then set the database password secret,

 database:
    build: 
       context: ./database
    image: atsea_db
    environment:
      POSTGRES_USER: gordonuser
      POSTGRES_DB_PASSWORD_FILE: /run/secrets/postgres_password
      POSTGRES_DB: atsea
    ports:
      - "5432:5432" 
    networks:
      - back-tier
    secrets:
      - postgres_password

and I make the postgres_password secret available to the application server.

 appserver:
    build:
       context: .
       dockerfile: app/Dockerfile
    image: atsea_app
    ports:
      - "8080:8080" 
      - "5005:5005"
    networks:
      - front-tier
      - back-tier
    secrets:
      - postgres_password

As you can see, you can set secrets at the command line and programmatically in the a compose file.

Docker Enterprise Edition (formerly known as Docker Datacenter) fully incorporates secrets management through creation, update and removal of secrets. In addition Docker EE supports authorization, rotation and auditing of secrets. Creating a secret in Docker Enterprise Edition is accomplished by clicking on the Resources tab and then the Secrets menu item.

Docker secrets

Create the secret by entering the name and the value and clicking Create. In this example, I’m using the secret for the PostgreSQL password in the AtSea application.

 Docker secrets

Docker secrets

Using Secrets

In order to use the Secret containing the certificate for nginx, I configured the nginx.conf file to point at the secret in the nginx container.

server {
        listen 443;
        ssl on;
        ssl_certificate /run/secrets/revprox_cert;
        ssl_certificate_key /run/secrets/revprox_key;
        server_name atseashop.com;
        access_log /dev/stdout;
        error_log /dev/stderr;

        location / {
            proxy_pass http://appserver:8080;
        }
    }

The AtSea application uses the postgres_password secret to connect to the database. This is done by reading the secret from the container and setting it to Spring-Boot’s DataSourceProperties class in the JpaConfiguration.java file.

// Set password to connect to postgres using Docker secrets.
try(BufferedReader br = new BufferedReader(new  FileReader("/run/secrets/postgres_password"))) 
{
      StringBuilder sb = new StringBuilder();
      String line = br.readLine();

      while (line != null) {
           sb.append(line);
           sb.append(System.lineSeparator());
           line = br.readLine();
      }
dataSourceProperties.setDataPassword(sb.toString());
      } catch (IOException e) {
         System.err.println("Could not successfully load DB password file");
      } 
return dataSourceProperties;
}

Learn more about Docker secrets:

, , , ,

Sophia Parafina

Securing the AtSea App with Docker Secrets


2 Responses to “Securing the AtSea App with Docker Secrets”

  1. Gerard Krupa

    Might it not be simpler to expose the secrets as an application-<profile-name>.yaml or a shell script that can be sourced rather than add chunks of custom secret-reading code to a Spring Boot application?

    Reply
  2. Laurent Magnin

    @Gerard,
    fyi, to solve that issue, we do use, as you suggested, an entrypoint script to setup the environment variables from the secret files (https://github.com/Logimethods/smart-meter/pull/4/files).
    Best regards,
    Laurent

    Reply

Leave a Reply to Laurent Magnin

Click here to cancel reply.

Get the Latest Docker News by Email

Docker Weekly is a newsletter with the latest content on Docker and the agenda for the upcoming weeks.