0

How to open an SSH tunnel during the build process of PostGIS container build?

I need to SSH tunnel to database, so I can create dump, then restore in container.

With other docker containers, I usually create a startup.sh then run from Dockerfile. However, to run startup scripts in PostGIS container we need to add the script to /docker-entrypoint-initdb.d folder.

The problem with this is, the script runs as user postgres with a user id of 999. I need to run as root with userid of 0 to execute ssh commands.

 Instructions run from the Dockerfile execute under the root user, but again once the scripts are run from /docker-entrypoint-initdb.d, they are run under the postgres user.

 If I run docker exec -it postgis_container bash, I am in bash as the root user and I can execute all the commands I need. However, I do not want to do this. I want to just execute docker-compose up and allow the docker compose configurations, the Dockerfile and possible any startup script to do the rest.

I know I can install OpenSSH and run tunnel from Dockerfile but connecting to a server the first time brings up the known_host prompt. I can user ssh-keyscan -H some_server >> /root/.ssh/known_hosts or even make a volume from the host machine of my ~/.ssh folder, that containers working a known_host file but the error I get is:

Dockerfile

RUN echo "Install OpenSSH \n" \
&& apt-get -y update \
&& apt-get install -y openssh-client \
&& echo "Config SSH \n" \
&& mkdir /root/.ssh && touch /root/.ssh/id_rsa-dev \
&& chmod 700 /root/.ssh/id_rsa-dev \
&& touch /root/.ssh/known_hosts \
&& touch /root/.ssh/config \
&& ssh-keyscan -H some_server.com >> /root/.ssh/known_hosts \
&& echo "Tunnel to DB \n" \
&& ssh -N -L 9001:some_other_server.com:5432 some_user@some_server.com -i /root/.ssh/id_rsa-dev & \
&& echo "Setup for dump and restore \n" \
&& cd /root/dump \
&& date_today=$(date +%F) \
&& echo "Createing dump file from dev db name = dev_db_$date_today.sql" \
&& export PGPASSWORD=${DEV_DB_PASSWORD} \
&& pg_dump -Fc -v -U dbuser -d dev_db -p 9001 -h 0.0.0.0 > ./dev_db_$date_today.sql \
&& export PGPASSWORD=$POSTGRES_PASSWORD \
&& echo "Restoring db" \
&& pg_restore -Fc -v -U dbuser -d dev_db_docker_local ./dev_db_$date_today.sql

Error from output

0.335 Warning: Permanently added the ECDSA host key for IP address ‘111.222.333.444’ to the list of known hosts.                                                                                                                                                                                   
#0 0.418 Authorized uses only. All activity may be monitored and reported.                                                                                                                                                                                                                         
#0 0.418 Load key "/root/.ssh/id_rsa-dev": invalid format
#0 0.418 some_user@some_server.com: Permission denied (publickey).

However, again, if I run docker exec -it postgis_container bash, then execute the exact same commands, I am able to open the ssh tunnel, dump and restore.

startup.sh

#!/usr/bin/env bash
cho "Install OpenSSH
apt-get -y update
apt-get install -y openssh-client
echo "Config SSH
mkdir /root/.ssh && touch /root/.ssh/id_rsa-dev
chmod 700 /root/.ssh/id_rsa-dev
touch /root/.ssh/known_hosts
touch /root/.ssh/config
ssh-keyscan -H some_server.com >> /root/.ssh/known_hosts
echo "Tunnel to DB
ssh -N -L 9001:some_other_server.com:5432 some_user@some_server.com -i /root/.ssh/id_rsa-dev &
echo "Setup for dump and restore
cd /root/dump
date_today=$(date +%F)
echo "Createing dump file from dev db name = dev_db_$date_today.sql"
export PGPASSWORD=${DEV_DB_PASSWORD}
pg_dump -Fc -v -U dbuser -d dev_db -p 9001 -h 0.0.0.0 > ./dev_db_$date_today.sql
export PGPASSWORD=$POSTGRES_PASSWORD
echo "Restoring db"
pg_restore -Fc -v -U dbuser -d dev_db_docker_local ./dev_db_$date_today.sql

I would prefer to be able to run my startup.sh script from /docker-entrypoint-initdb.d folder as a root user. But If I can not, then would like to be able to added all the steps to Dockerfile

Any help would be greatly appreciated.


Note:

I asked a question here.

I was trying to find out how to get my startup script to run as root, but realized the question did not give enough context so I created this post. I mention this because setting user root or 0, wether in the Dockerfile or the docker-compose.yml does not solve my problem.

If I try to run startup.sh from /docker-entrypoint-initdbd:

sudo is not available. su is available, but I do not know root password. gosu is available but when I used that it give an error along the lines of operation not permitted.

Update 1:

Seems like this is an issue. The postgres docker github says you can not run as root from /docker-entrypoint-initdb.d.

https://github.com/docker-library/postgres/issues/973

But something seems weird about that. I figure there has got to be a way around this. Or maybe some best practice that address this use case. I imagine I am not the only one who has run into an issue like this.

Update 2:

I just realized running the commands in Dockerfile will not work because postgres would not have been started yet. And I need to run psql after I open the tunnel. So I have to run from /docker-entrypoint-initdb.d folder or figure out some way to get startup.sh to run after postgis container finishes its default start up processes.

Appearently this was not a problem a few years ago, but I believe there was a move to stop the use of root access during the build start up process in the /docker-entrypoint-initdb.d for security reasons. But there was no suggested work around.

user2517182
  • 1,241
  • 3
  • 15
  • 37
  • That really is one enormous `RUN` statement. Are you sure you want that all as one shot? Normally it's split up into different operations, like the `apt` calls, then the environment, then other things. – tadman Dec 19 '22 at 21:14
  • I really did this for the stackoverflow example. I have split them up before. As a matter of fact; I usually just have a few operations in the `Dockerfile` then call `CMD bash /root/startup.sh` at the end. But the issue is, I can not do that because the process run as user postgres. – user2517182 Dec 19 '22 at 23:09
  • @tadman continuing with my reply, the issue is, I can not do run my commands because the process run as user postgres in the`/docker-entrypoint-initdb.d` folder. That is different that running `docker exec -it db bash` because then I can execute the `startup.sh` and everything works – user2517182 Dec 19 '22 at 23:23
  • Do you know what the default root password is for a running PostGIS container? – user2517182 Dec 20 '22 at 02:34
  • Only for check if I understood your problem, when you run commands SSH tunnel, dump, and restore from the /docker-entrypoint-initdb.d folder, they aren't executing correctly, but when you run manually from the container, they works correctly, right? – Julien Ambrosio Dec 22 '22 at 16:01
  • @JulienAmbrosio, yes this is correct. This is because when running from `/docker-entrypoint-initdb.d` vs `exec bash`, it is being run as different users with different permission. – user2517182 Jan 09 '23 at 14:06
  • I usually do it in two steps: 1) executing the dump (from a docker container if needed) and 2) executing the restore. For this, I embed the dump file using a single COPY statement in a Dockerfile along with an init script which calls `pg_restore` or `psql` to actually restore your dump. – swiss_knight Jan 24 '23 at 20:38
  • @s.k yes I do something similar to this. This is how I have it currently working. The problem is this has to be done after the docker build. I would like to run these commands automatically when building. However, at the point these commands need to run, the build is not executing as root, thus the commands fail because of permissions. – user2517182 Jan 25 '23 at 14:43

0 Answers0