postgresqldockerdocker-composedocker-secrets

I can't get user recognized using Docker secrets with Docker Compose and Postgres


I'm running the command:

docker exec -it db psql --user $(< postgres_user.txt)

and I'm getting the error:

/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  database "my_postgres_user" does not exist

This is my compose.yaml file:

services:
  db:
    container_name: db
    image: postgres:16
    environment:
      POSTGRES_USER_FILE: /run/secrets/postgres_user
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
      POSTGRES_DB_FILE: /run/secrets/postgres_db
    secrets:
      - postgres_user
      - postgres_password
      - postgres_db
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data

secrets:
  postgres_user:
    file: postgres_user.txt
  postgres_password:
    file: postgres_password.txt
  postgres_db:
    file: postgres_db.txt

volumes:
  pgdata: {}

The secrets files are in the same directory as the compose.yaml file. Their contents each look like this postgres_user.txt file (with no additional spaces or newline characters):

my_postgres_user

The example for secrets in the Docker docs looks like this:

services:
   db:
     image: mysql:latest
     volumes:
       - db_data:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD_FILE: /run/secrets/db_password
     secrets:
       - db_root_password
       - db_password

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
     secrets:
       - db_password


secrets:
   db_password:
     file: db_password.txt
   db_root_password:
     file: db_root_password.txt

volumes:
    db_data:

and in the Docker Postgres docs, there is this example using secrets:

docker run --name some-postgres -e POSTGRES_PASSWORD_FILE=/run/secrets/postgres-passwd -d postgres

but this is a run command and password secret and things don't seem to translate (i.e. using the -e flag) when using an exec command needing a user secret.

I've tried both having the secrets files as the are now, in the same directory as the compose.yaml as well as in a /secrets directory, e.g. /secrets/postgres_user.text and ./secrets/postgres_user.txt, but the result is the same.

Looking at Inspect in Docker Desktop, I see this:

    "Config": {
        "Hostname": "c974321g8365",
        "Domainname": "",
        "User": "",
        "AttachStdin": false,
        "AttachStdout": true,
        "AttachStderr": true,
        "ExposedPorts": {
            "5432/tcp": {}
        },
        "Tty": false,
        "OpenStdin": false,
        "StdinOnce": false,
        "Env": [
            "POSTGRES_USER_FILE=/run/secrets/postgres_user",
            "POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password",
            "POSTGRES_DB_FILE=/run/secrets/postgres_db",
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/16/bin",
            "GOSU_VERSION=1.17",
            "LANG=en_US.utf8",
            "PG_MAJOR=16",
            "PG_VERSION=16.2-1.pgdg120+2",
            "PGDATA=/var/lib/postgresql/data"
        ],

where User is blank, although I don't know if that represents the problem, i.e. if it should be "User": "my_postgres_user",.

All three secrets files are listed under Mounts in Inspect and since the error message uses my_postgres_user which is from the secrets file postgres_user.txt, it seems clear it is finding the file. I just can determine why the role isn't being created.


Solution

  • @jjanes pointed out in a comment that the error was saying the "database" doesn't exist, not the "role", which I had overlooked. So I added the secrets file for the database after the user and it worked. The command I ended up with is:

    docker exec -it db psql -U $(< postgres_user.txt) $(< postgres_db.txt)
    

    In this way, I should be able to utilize secrets for user, database, and password in place of environment variables.

    Update: If I want to keep my secrets file in a /secrets directory in the project root directory, I change my compose.yaml file lower secrets section to this:

    secrets:
      postgres_user:
        file: ./secrets/postgres_user.txt
      postgres_password:
        file: ./secrets/postgres_password.txt
      postgres_db:
        file: ./secrets/postgres_db.txt
    

    and I change the docker exec command as follows:

    docker exec -it db psql -U $(< ./secrets/postgres_user.txt) $(< ./secrets/postgres_db.txt)
    

    Update 2: For anyone curious, looking at the Docker Desktop "Inspect" again now that it is working, "Config" still shows "User": "",.