3

Using Pulumi, how do I provision a Postgres database using Docker without exposing the postgres password?

Currently, I can view the password when inspecting the container's environment variables.

import * as docker from '@pulumi/docker'
import * as pulumi from '@pulumi/pulumi'
import network from '../network'
import { Volume } from '../volumes'

const container_name = `${pulumi.getProject()}-postgres`

const postgresConfig = new pulumi.Config('postgres')

const postgres = pulumi
    .all([postgresConfig.requireSecret('password')])
    .apply(([password]) => {
        const env = {
            POSTGRES_DB: postgresConfig.require('db'),
            POSTGRES_USER: postgresConfig.require('user'),
            POSTGRES_PASSWORD: password,
        }

        return new docker.Container(container_name, {
            name: container_name,
            image: 'postgres:latest',
            restart: 'always',
            ports: [
                {
                    internal: 5432,
                    external: 5432,
                },
            ],
            networksAdvanced: [
                {
                    name: network.name,
                },
            ],
            volumes: [
                {
                    volumeName: Volume.postgres,
                    containerPath: '/var/lib/postgres/data',
                },
            ],
            healthcheck: {
                interval: '10s',
                retries: 10,
                tests: ['pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB'],
                timeout: '2s',
            },
            envs: [
                `POSTGRES_DB=${env.POSTGRES_DB}`,
                `POSTGRES_USER=${env.POSTGRES_USER}`,
                `POSTGRES_PASSWORD=${env.POSTGRES_PASSWORD}`,
            ],
        })
    })

export default postgres
Zeitounator
  • 38,476
  • 7
  • 53
  • 66
Ryan Prentiss
  • 1,492
  • 2
  • 25
  • 46

1 Answers1

1

In your example, the secrets are encrypted by Pulumi and are not visible in plaintext. However, when you pass them to the Docker container, they become available in plaintext in the environment variables.

To stop the password being visible in plaintext, you can use a Docker Secret to encrypt those values, but docker secrets is only available on Docker Swarm

Quote from the above page:

Docker secrets are only available to swarm services, not to standalone containers. To use this feature, consider adapting your container to run as a service. Stateful containers can typically run with a scale of 1 without changing the container code.

If you do decide to use Docker Swarm, you can do so on a standalone node by running:

docker swarm init

Then define your container as a service.

import * as pulumi from "@pulumi/pulumi";
import * as docker from "@pulumi/docker";

const container_name = `${pulumi.getProject()}-postgres`;
const postgresConfig = new pulumi.Config("postgres");

const password = postgresConfig.requireSecret("password");
const env = {
  POSTGRES_DB: postgresConfig.require("db"),
  POSTGRES_USER: postgresConfig.require("user"),
  POSTGRES_PASSWORD: password,
};

const secret = new docker.Secret("password", {
    name: "postgres-password",
    data: password.apply((pwd) => Buffer.from(pwd, 'utf8').toString('base64'))
})

const svc = new docker.Service(container_name, {
    endpointSpec: {
        ports: [{
            targetPort: 5432,
            publishedPort: 5432,
            publishMode: "ingress"
        }]
    },
    taskSpec: {
        containerSpec: {
            image: "postgres:latest",
            secrets: [{
                secretId: secret.id,
                fileName: "postgres-password",
                secretName: secret.name,
            }],
            env: {
                POSTGRES_DB: env.POSTGRES_DB,
                POSTGRES_USER: env.POSTGRES_USER,
                POSTGRES_PASSWORD_FILE: "/run/secrets/postgres-password",
            },
        }
    }
})
jaxxstorm
  • 12,422
  • 5
  • 57
  • 67