Hi I'm using spring-boot-docker-compose to have a postgres database start when the app starts but getting error at startup
java.lang.IllegalStateException: No POSTGRES_PASSWORD defined
This is due to PostgresEnvironment extracting environment variables but assuming there is a POSTGRES_PASSWORD environment variable.
I am using the supported POSTGRES_PASSWORD_FILE environment variable instead, which is how you can keep secrets out of version control.
Steps to reproduce
- Configure pom.xml
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
...
- Add docker-compose.yml in the root project folder
version: '3.8'
services:
db:
image: postgres:14.5
restart: always
environment:
POSTGRES_DB: mydb
POSTGRES_USER: myuser
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
ports:
- 5432:5432
secrets:
- db_password
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
secrets:
db_password:
file: src/main/resources/postgres_password.txt
- Save a secrets file
- Save the postgres password in the Spring Boot app under
src/main/resources/postgres_password.txt - Run the app
- Expecting the app to start but instead getting
java.lang.IllegalStateException: No POSTGRES_PASSWORD defined
Running docker compose up works fine and the container starts.
Spring Boot version: 3.1.1 Java version: openjdk 17.0.8.1
Comment From: mhalbritter
Hello,
currently we don't have support for POSTGRES_PASSWORD_FILE. You have to use POSTGRES_PASSWORD, otherwise it won't work.
We intended the docker compose support for development - what is the reason you don't want to have the credentials in the docker compose file itself? They shouldn't be secret, as they are for development only.
Comment From: derylspielman
A password is a password and I wouldn't want anyone checking in any kind of passwords in to version control regardless of the environment as it poses security risk. Not only for internal or external hackers that may have come across the password and attempt to exploit postgres on a developer machine, but also just general avoiding habit of any devs checking in passwords.
I might look in to the code to see how the postgres password is used but have to see how downstream use is affected. Essentially it's just an extra check with following logic:
If POSTGRES_PASSWORD_FILE then parse the file location and read the line in file.
Comment From: philwebb
I might look in to the code to see how the postgres password is used but have to see how downstream use is affected.
The code you want to look at is here. The problem you're likely to face is that the file isn't on the local filesystem, it's inside the running container. We currently don't surface any API to get to container files. To do that, you'll probably need changes to the DockerCompose interface and the DefaultDockerCompose implementation class that calls the docker CLI.
Comment From: quaff
The problem you're likely to face is that the file isn't on the local filesystem, it's inside the running container. We currently don't surface any API to get to container files. To do that, you'll probably need changes to the
DockerComposeinterface and theDefaultDockerComposeimplementation class that calls thedockerCLI.
The file exists on classpath resources/postgres_password.txt then mount to container.
Comment From: wilkinsona
The file exists on classpath
Is that always the case? I had assumed that was only for example purposes. This comment from @derylspielman added to that:
I wouldn't want anyone checking in any kind of passwords in to version control
Perhaps src/main/resources/postgres_password.txt is covered by .gitignore, but I don't think we have the full picture here.
Comment From: mhalbritter
The main problem here is that we don't parse the compose.yaml file. We rely on docker inspect to extract the information about the container. We could then find out that there's a POSTGRES_PASSWORD_FILE env variable, and it points to a file. But we can't directly read that file, as it's inside the container. And I'm not convinced that implementing more code to extract that file out of the container is worth it. In this example, the password isn't in the compose.yaml file, but it's contained in a file on the classpath (which is even worse, because now it's included in the JAR file).
But even if this file is in the .gitignore and is somehow excluded from landing inside the JAR, this means that developers have to create that file before they can start developing. And this goes against our goal of easing developer experience.
I just can't see the benefit of not including a development time only password inside the POSTGRES_PASSWORD variable. But if you really really want to do that, you should better rely on .env files and environment substitution: https://docs.docker.com/compose/environment-variables/set-environment-variables/
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: derylspielman
Sorry what information are you waiting on from me?
I have a secrets.properties that is git ignored in the resources folder for other dev secrets and optionally imported from main application.properties. Could a work around be that I put a spring.docker-compose.postgres-password in there and the framework will inject that environment variable when it's running docker compose?
Comment From: wilkinsona
Sorry what information are you waiting on from me?
Some further information about how you're managing the secrets file – which you've now provided, thank you – and a response to Moritz's comment above. You haven't addressed his suggestion to use a .env file and environment substitution.
Could a work around be that I put a spring.docker-compose.postgres-password in there and the framework will inject that environment variable when it's running docker compose?
I think it's unlikely that we'd implement this. It feels like we'd be reinventing something that Docker Compose already supports through a .env file.
Comment From: derylspielman
I mean...the code is literally assuming a specific way of injecting the password and there's one other way supported by postgres official image. I don't think it has anything to do with docker compose personally.
Comment From: wilkinsona
We've already explained above how Docker Compose adds to the complexity. To fully support the feature, we'd have to read the POSTGRES_PASSWORD_FILE environment variable, either by parsing the yaml or by connecting to the running container. We'd then have to read that file in the container to determine the password. Our opinion is that this would add a significant amount of complexity for minimal benefit.
If you really want to use a password file you could do so by writing your own DockerComposeConnectionDetailsFactory for Postgres and registering it in spring.factories.
I'm going to close this now as this doesn't seem to be going anywhere. We still haven't heard why the .env file approach isn't suitable for example.