Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker Compose option to generate random passwords #76

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .env.use-generated-passwords
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Container names
NGINX_CONTAINER_NAME=nginx
REDIS_CONTAINER_NAME=redis
POSTGRESQL_CONTAINER_NAME=db
SOLR_CONTAINER_NAME=solr
DATAPUSHER_CONTAINER_NAME=datapusher
CKAN_CONTAINER_NAME=ckan
WORKER_CONTAINER_NAME=ckan-worker

# Host Ports
CKAN_PORT_HOST=5000
NGINX_PORT_HOST=81
NGINX_SSLPORT_HOST=8443

# CKAN databases
POSTGRES_USER=postgres
POSTGRES_DB=postgres
POSTGRES_HOST=db
CKAN_DB_USER=ckandbuser
CKAN_DB=ckandb
DATASTORE_READONLY_USER=datastore_ro
DATASTORE_DB=datastore

# Test database connections
TEST_CKAN_SQLALCHEMY_URL=postgres://ckan:ckan@db/ckan_test
TEST_CKAN_DATASTORE_WRITE_URL=postgresql://ckan:ckan@db/datastore_test
TEST_CKAN_DATASTORE_READ_URL=postgresql://datastore_ro:datastore@db/datastore_test

# CKAN core
CKAN_VERSION=2.10.0
CKAN_SITE_ID=default
CKAN_SITE_URL=https://localhost:8443
CKAN_PORT=5000
CKAN_PORT_HOST=5000
CKAN___BEAKER__SESSION__SECRET=CHANGE_ME
# See https://docs.ckan.org/en/latest/maintaining/configuration.html#api-token-settings
CKAN___API_TOKEN__JWT__ENCODE__SECRET=string:CHANGE_ME

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably set these as well.

CKAN___API_TOKEN__JWT__DECODE__SECRET=string:CHANGE_ME
CKAN_SYSADMIN_NAME=ckan_admin
[email protected]
CKAN_STORAGE_PATH=/var/lib/ckan
CKAN_SMTP_SERVER=smtp.corporateict.domain:25
CKAN_SMTP_STARTTLS=True
CKAN_SMTP_USER=user
CKAN_SMTP_PASSWORD=pass
CKAN_SMTP_MAIL_FROM=ckan@localhost
TZ=UTC

# Solr
SOLR_IMAGE_VERSION=2.10-solr9
CKAN_SOLR_URL=http://solr:8983/solr/ckan
TEST_CKAN_SOLR_URL=http://solr:8983/solr/ckan

# Redis
REDIS_VERSION=6
CKAN_REDIS_URL=redis://redis:6379/1
TEST_CKAN_REDIS_URL=redis://redis:6379/1

# Datapusher
DATAPUSHER_VERSION=0.0.20
CKAN_DATAPUSHER_URL=http://datapusher:8800
CKAN__DATAPUSHER__CALLBACK_URL_BASE=http://ckan:5000
DATAPUSHER_REWRITE_RESOURCES=True
DATAPUSHER_REWRITE_URL=http://ckan:5000

# NGINX
NGINX_PORT=80
NGINX_SSLPORT=443

# Extensions
CKAN__PLUGINS="envvars image_view text_view recline_view datastore datapusher"
CKAN__HARVEST__MQ__TYPE=redis
CKAN__HARVEST__MQ__HOSTNAME=redis
CKAN__HARVEST__MQ__PORT=6379
CKAN__HARVEST__MQ__REDIS_DB=1
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ _service-provider/*
_solr/schema.xml
_src/*
local/*

# Docker Compose environment and password files
.env
.pw
docker-compose.yml.ORIG
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ more information.

## 4. Install (build and run) CKAN plus dependencies

#### Generate Randomised passwords mode

For additional security it may be a better option to generate randomised passwords for the database users and the for the initial CKAN application sysadmin user. Here are the users that will have randomised
passwords generated:

* The Postgres system superuser (user=`POSTGRES_USER` , password=`POSTGRES_PASSWORD`)
* The database user that owns the CKAN database (user=`CKAN_DB_USER` , password=C`KAN_DB_PASSWORD`)
* The database user that has read-access to the Datastore database (user=`DATASTORE_READONLY_USER` , password=`DATASTORE_READONLY_PASSWORD`)
* The CKAN application System Administrator user (user=`CKAN_SYSADMIN_NAME` ,password=`CKAN_SYSADMIN_PASSWORD`)

You can do this by the following:

* remove all containers, images, networks, volumes plus run a `docker system prune`
* generate the passwords by running `generate_passwords.sh` this will create a file called `.pw`
* rename the `docker-compose-use-generated-passwords.yml` file to `docker-compose.yml`. You may wish to save the docker-compose.yml file beforehand.
* rename the `.env.use-generated-passwords` file to `.env`. You should save the .env file beforehand.
* build and run the docker compose stack as per normal. The `ckan_admin` user password will be located in the `.pw` file

#### Base mode

Use this if you are a maintainer and will not be making code changes to CKAN or to CKAN extensions
Expand Down
115 changes: 115 additions & 0 deletions docker-compose-use-generated-passwords.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
version: "3"


volumes:
ckan_storage:
pg_data:
solr_data:

services:

nginx:
container_name: ${NGINX_CONTAINER_NAME}
build:
context: nginx/
dockerfile: Dockerfile
networks:
- webnet
- ckannet
depends_on:
ckan:
condition: service_healthy
ports:
- "0.0.0.0:${NGINX_SSLPORT_HOST}:${NGINX_SSLPORT}"

ckan:
container_name: ${CKAN_CONTAINER_NAME}
build:
context: ckan/
dockerfile: Dockerfile
args:
- TZ=${TZ}
networks:
- ckannet
- dbnet
- solrnet
- redisnet
env_file:
- .env
- .pw

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't safe.

This is passing in the database superuser password into the CKAN instance, where it should only have access to the specific urls that are needed to connect to the database.

depends_on:
db:
condition: service_healthy
solr:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ckan_storage:/var/lib/ckan
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:5000"]

datapusher:
container_name: ${DATAPUSHER_CONTAINER_NAME}
networks:
- ckannet
- dbnet
image: ckan/ckan-base-datapusher:${DATAPUSHER_VERSION}
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:8800"]

db:
container_name: ${POSTGRESQL_CONTAINER_NAME}
build:
context: postgresql/
networks:
- dbnet
environment:
- POSTGRES_USER
#- POSTGRES_PASSWORD
- POSTGRES_DB
- CKAN_DB_USER
#- CKAN_DB_PASSWORD
- CKAN_DB
- DATASTORE_READONLY_USER
#- DATASTORE_READONLY_PASSWORD
- DATASTORE_DB
env_file:
- .pw
volumes:
- pg_data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}", "-d", "${POSTGRES_DB}"]

solr:
container_name: ${SOLR_CONTAINER_NAME}
networks:
- solrnet
image: ckan/ckan-solr:${SOLR_IMAGE_VERSION}
volumes:
- solr_data:/var/solr
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:8983/solr/"]

redis:
container_name: ${REDIS_CONTAINER_NAME}
image: redis:${REDIS_VERSION}
networks:
- redisnet
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "-e", "QUIT"]

networks:
webnet:
ckannet:
solrnet:
internal: true
dbnet:
internal: true
redisnet:
internal: true
9 changes: 6 additions & 3 deletions docker-compose.yml

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this committed by accident? At a glance, this looks like the generated passwords Compose file was used to overwrite the regular Compose file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think so...here are the last commits to docker-compose.yml:

Screenshot 2023-08-29 at 4 06 18 pm

Copy link

@themowski themowski Aug 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I meant, was it added into this PR (committed to this branch) by accident?

Based on the other feedback, it seems like the auto-generated passwords will be the default behavior in the future, so presumably this comment is moot anyways.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK, if you look at the README in the PR you will see the instructions:

Screenshot 2023-08-29 at 5 14 44 pm

At the moment you need to explicitly override the docker-compose.yml file when wanting to use more secure passwords, however after the Dev meeting this afternoon it was decided that secure passwords will be the default when this is merged

Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ services:
- redisnet
env_file:
- .env
- .pw
depends_on:
db:
condition: service_healthy
Expand Down Expand Up @@ -67,14 +68,16 @@ services:
- dbnet
environment:
- POSTGRES_USER
- POSTGRES_PASSWORD
#- POSTGRES_PASSWORD
- POSTGRES_DB
- CKAN_DB_USER
- CKAN_DB_PASSWORD
#- CKAN_DB_PASSWORD
- CKAN_DB
- DATASTORE_READONLY_USER
- DATASTORE_READONLY_PASSWORD
#- DATASTORE_READONLY_PASSWORD
- DATASTORE_DB
env_file:
- .pw
volumes:
- pg_data:/var/lib/postgresql/data
restart: unless-stopped
Expand Down
36 changes: 36 additions & 0 deletions generate_passwords.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import base64
import os

fn = ".pw"
vn = {}

pwvars = ["POSTGRES_PASSWORD", "CKAN_DB_PASSWORD", "DATASTORE_READONLY_PASSWORD","CKAN_SYSADMIN_PASSWORD"]

print("[setup_passwords] attempting to setup secure passwords")

with open(fn, 'w') as f:
f.truncate(0)
for pwvar in pwvars:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to use https://docs.python.org/3/library/secrets.html#secrets.token_urlsafe secrets.token_urlsafe, as /dev/urandom is somewhat platform dependent.

with open('/dev/urandom', 'rb') as rand_file:
pw = base64.urlsafe_b64encode(rand_file.read(12)).decode('utf-8')
f.write(f"{pwvar}={pw}\n")
vn[pwvar] = pw

POSTGRES_PASSWORD = vn["POSTGRES_PASSWORD"]
CKAN_DB_PASSWORD = vn["CKAN_DB_PASSWORD"]
DATASTORE_READONLY_PASSWORD = vn["DATASTORE_READONLY_PASSWORD"]
CKAN_SYSADMIN_PASSWORD = vn["CKAN_SYSADMIN_PASSWORD"]

CKAN_DB_USER = os.environ.get('CKAN_DB_USER')
CKAN_DB = os.environ.get('CKAN_DB')
DATASTORE_DB_USER = os.environ.get('DATASTORE_DB_USER')
DATASTORE_READONLY_USER = os.environ.get('DATASTORE_READONLY_USER')
DATASTORE_DB = os.environ.get('DATASTORE_DB')
POSTGRES_HOST = os.environ.get('POSTGRES_HOST')

with open(fn, 'a') as f:
f.write(f"CKAN_SQLALCHEMY_URL=postgresql://{CKAN_DB_USER}:{CKAN_DB_PASSWORD}@{POSTGRES_HOST}/{CKAN_DB}\n")
f.write(f"CKAN_DATASTORE_WRITE_URL=postgresql://{CKAN_DB_USER}:{CKAN_DB_PASSWORD}@{POSTGRES_HOST}/{DATASTORE_DB}\n")
f.write(f"CKAN_DATASTORE_READ_URL=postgresql://{DATASTORE_READONLY_USER}:{DATASTORE_READONLY_PASSWORD}@{POSTGRES_HOST}/{DATASTORE_DB}\n")

print("[setup_passwords] password file: '.pw' created successfully")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably print out the ckan sysadmin password on the console, and note where it's actually saved.

9 changes: 9 additions & 0 deletions generate_passwords.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh

set -a
. ./.env
pwfile=".pw"
touch ${pwfile}; chmod 600 ${pwfile}
python3 ./generate_passwords.py
chmod 400 ${pwfile}
sleep 1