diff --git a/.env.example b/.env.insecure similarity index 100% rename from .env.example rename to .env.insecure diff --git a/.env.secure b/.env.secure new file mode 100644 index 00000000..7c819f3f --- /dev/null +++ b/.env.secure @@ -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 +CKAN___API_TOKEN__JWT__DECODE__SECRET=string:CHANGE_ME +CKAN_SYSADMIN_NAME=ckan_admin +CKAN_SYSADMIN_EMAIL=your_email@example.com +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 diff --git a/.gitignore b/.gitignore index a3d88d50..d9510f5e 100755 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,9 @@ _service-provider/* _solr/schema.xml _src/* local/* + +# Docker Compose environment and password files .env +.ckpw +.dbpw +docker-compose.yml.ORIG diff --git a/README.md b/README.md index f48b18ba..1a532df6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # Docker Compose setup for CKAN - * [Overview](#overview) * [Installing Docker](#installing-docker) * [docker compose vs docker-compose](#docker-compose-vs-docker-compose) @@ -45,23 +44,56 @@ versions for client and server. ## 3. docker compose *vs* docker-compose All Docker Compose commands in this README will use the V2 version of Compose ie: `docker compose`. The older version (V1) -used the `docker-compose` command. Please see [Docker Compose](https://docs.docker.com/compose/compose-v2/) for -more information. +used the `docker-compose` command. Please see [Docker Compose](https://docs.docker.com/compose/compose-v2/) for more information. ## 4. Install (build and run) CKAN plus dependencies -#### Base mode +#### Generate randomised passwords mode (secure/default mode) + +For additional security the default option is to run in "secure" mode. To do this a script will need to be run to generate randomised passwords for the database users and for the initial CKAN application sysadmin user (ckan_admin). It will also generate some other parameters detailed below: + +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: `CKAN_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`) + +There are other configuration parameters that will also have random secrets generated. They are as follows: +* `CKAN___BEAKER__SESSION__SECRET` +* `CKAN___API_TOKEN__JWT__ENCODE__SECRET` +* `CKAN___API_TOKEN__JWT__DECODE__SECRET` + +Also, database URL's will need to include these new passwords so the values for this configuration parameters will be added to the generated (CKAN) file +* `CKAN_SQLALCHEMY_URL` +* `CKAN_DATASTORE_WRITE_URL` +* `CKAN_DATASTORE_READ_URL` + +You can do this by the following: -Use this if you are a maintainer and will not be making code changes to CKAN or to CKAN extensions +* generate the passwords by running `generate_passwords.sh` this will create two files: `.ckpw` and `.dbpw` +* by default the `docker-compose.yml` file is set to secure mode. +* You need to make a copy of `.env.secure` as `.env` +* if you make any subsequent changes to the `docker-compose.yml` file you can always revert back to the original file by referencing `docker-compose.secure.yml` +* by default the `.env` file is set to secure mode. +* if you make changes to the `.env` file you can always revert back to the original file by referencing `.env.secure` +* build and run the docker compose stack as per normal. +* the `ckan_admin` user password will be located in the `.ckpw` file. It will also be displayed on the terminal when running `generate_passwords.sh` -Copy the included `.env.example` and rename it to `.env`. Modify it depending on your own needs. +#### Insecure mode (the old legacy mode) + +Use this if you do not wish to use secure passwords ie: how it used to be + +Copy the included `.env.insecure` to `.env`. Modify it depending on your own needs. It's wise to keep the original `.env.secure` file in case +you need to revert back to it or reference from it + +Copy the included `docker-compose.insecure.yml` and to `docker-compose.yml`. Modify it depending on your own needs. Please note that when accessing CKAN directly (via a browser) ie: not going through NGINX you will need to make sure you have "ckan" set up to be an alias to localhost in the local hosts file. Either that or you will need to change the `.env` entry for CKAN_SITE_URL Using the default values on the `.env.example` file will get you a working CKAN instance. There is a sysadmin user created by default with the values defined in `CKAN_SYSADMIN_NAME` and `CKAN_SYSADMIN_PASSWORD`(`ckan_admin` and `test1234` by default). This should be obviously changed before running this setup as a public CKAN instance. -To build the images: +### To build the images: docker compose build @@ -84,6 +116,11 @@ After this step, CKAN should be running at `CKAN_SITE_URL`. Use this mode if you are making code changes to CKAN and either creating new extensions or making code changes to existing extensions. This mode also uses the `.env` file for config options. +Again, the default for Development mode is secure. Please see the section above on Secure mode. There are 2 reference compose `.yml` files + +* `docker-compose.dev.secure.yml` - this is the same as the default file `docker-compose.dev.yml` +* `docker-compose.dev.insecure.yml` - to be used if the insecure (ie: legacy) config is to be used + To develop local extensions use the `docker-compose.dev.yml` file: To build the images: diff --git a/ckan/setup/prerun.py.override b/ckan/setup/prerun.py.override index 3d686969..d8b79219 100644 --- a/ckan/setup/prerun.py.override +++ b/ckan/setup/prerun.py.override @@ -194,6 +194,13 @@ def create_sysadmin(): subprocess.call(command) print("[prerun] Made user {0} a sysadmin".format(name)) + # cleanup permissions + # We're running as root before pivoting to uwsgi and dropping privs + data_dir = "%s/storage" % os.environ['CKAN_STORAGE_PATH'] + + command = ["chown", "-R", "ckan:ckan", data_dir] + subprocess.call(command) + print("[prerun] Ensured storage directory is owned by ckan") if __name__ == "__main__": diff --git a/ckan/setup/start_ckan.sh.override b/ckan/setup/start_ckan.sh.override index 0c8409c9..5927deac 100755 --- a/ckan/setup/start_ckan.sh.override +++ b/ckan/setup/start_ckan.sh.override @@ -16,7 +16,7 @@ then fi # Run the prerun script to init CKAN and create the default admin user -sudo -u ckan -EH python3 prerun.py +python3 prerun.py echo "Set up ckan.datapusher.api_token in the CKAN config file" ckan config-tool $CKAN_INI "ckan.datapusher.api_token=$(ckan -c $CKAN_INI user token add ckan_admin datapusher | tail -n 1 | tr -d '\t')" @@ -51,7 +51,7 @@ then # Start supervisord supervisord --configuration /etc/supervisord.conf & # Start uwsgi - sudo -u ckan -EH uwsgi $UWSGI_OPTS + uwsgi $UWSGI_OPTS else echo "[prerun] failed...not starting CKAN." fi diff --git a/docker-compose-use-generated-passwords.yml b/docker-compose-use-generated-passwords.yml new file mode 100755 index 00000000..61ee1ce8 --- /dev/null +++ b/docker-compose-use-generated-passwords.yml @@ -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 + - .ckpw + 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: + - .ckpw + 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 diff --git a/docker-compose.dev.insecure.yml b/docker-compose.dev.insecure.yml new file mode 100755 index 00000000..0cf63126 --- /dev/null +++ b/docker-compose.dev.insecure.yml @@ -0,0 +1,76 @@ +version: "3" + +volumes: + ckan_storage: + pg_data: + solr_data: + +services: + + ckan-dev: + container_name: ${CKAN_CONTAINER_NAME} + build: + context: ckan/ + dockerfile: Dockerfile.dev + args: + - TZ=${TZ} + env_file: + - .env + depends_on: + db: + condition: service_healthy + solr: + condition: service_healthy + redis: + condition: service_healthy + ports: + - "0.0.0.0:${CKAN_PORT_HOST}:${CKAN_PORT}" + volumes: + - ckan_storage:/var/lib/ckan + - ./src:/srv/app/src_extensions + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:5000"] + + datapusher: + container_name: ${DATAPUSHER_CONTAINER_NAME} + 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/ + environment: + - POSTGRES_USER + - POSTGRES_PASSWORD + - POSTGRES_DB + - CKAN_DB_USER + - CKAN_DB_PASSWORD + - CKAN_DB + - DATASTORE_READONLY_USER + - DATASTORE_READONLY_PASSWORD + - DATASTORE_DB + 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} + 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} + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "-e", "QUIT"] \ No newline at end of file diff --git a/docker-compose.dev.secure.yml b/docker-compose.dev.secure.yml new file mode 100755 index 00000000..5c664604 --- /dev/null +++ b/docker-compose.dev.secure.yml @@ -0,0 +1,77 @@ +version: "3" + + +volumes: + ckan_storage: + pg_data: + solr_data: + +services: + + ckan-dev: + container_name: ${CKAN_CONTAINER_NAME} + build: + context: ckan/ + dockerfile: Dockerfile.dev + args: + - TZ=${TZ} + env_file: + - .env + - .ckpw + depends_on: + db: + condition: service_healthy + solr: + condition: service_healthy + redis: + condition: service_healthy + ports: + - "0.0.0.0:${CKAN_PORT_HOST}:${CKAN_PORT}" + volumes: + - ckan_storage:/var/lib/ckan + - ./src:/srv/app/src_extensions + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:5000"] + + datapusher: + container_name: ${DATAPUSHER_CONTAINER_NAME} + 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/ + environment: + - POSTGRES_USER + - POSTGRES_DB + - CKAN_DB_USER + - CKAN_DB + - DATASTORE_READONLY_USER + - DATASTORE_DB + env_file: + - .dbpw + 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} + 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} + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "-e", "QUIT"] \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 2bc7894c..0cf63126 100755 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -44,9 +44,15 @@ services: build: context: postgresql/ environment: - - DATASTORE_READONLY_PASSWORD + - POSTGRES_USER - POSTGRES_PASSWORD + - POSTGRES_DB + - CKAN_DB_USER - CKAN_DB_PASSWORD + - CKAN_DB + - DATASTORE_READONLY_USER + - DATASTORE_READONLY_PASSWORD + - DATASTORE_DB volumes: - pg_data:/var/lib/postgresql/data restart: unless-stopped diff --git a/docker-compose.insecure.yml b/docker-compose.insecure.yml new file mode 100755 index 00000000..0f5330fb --- /dev/null +++ b/docker-compose.insecure.yml @@ -0,0 +1,112 @@ +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 + 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 + 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 diff --git a/docker-compose.secure.yml b/docker-compose.secure.yml new file mode 100755 index 00000000..de5b5f8c --- /dev/null +++ b/docker-compose.secure.yml @@ -0,0 +1,112 @@ +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 + - .ckpw + 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_DB + - CKAN_DB_USER + - CKAN_DB + - DATASTORE_READONLY_USER + - DATASTORE_DB + env_file: + - .dbpw + 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 diff --git a/generate_passwords.py b/generate_passwords.py new file mode 100644 index 00000000..22dcb330 --- /dev/null +++ b/generate_passwords.py @@ -0,0 +1,89 @@ +import base64 +import os +import secrets +import logging + +# Password length set to 16 characters +plen = 16 + +def generate_passwords(variables): + passwords = {} + for variable in variables: + password = secrets.token_urlsafe(plen) + passwords[variable] = password + return passwords + +def write_passwords_to_file(passwords, filename): + try: + with open(filename, 'w') as f: + for variable, password in passwords.items(): + if variable == "CKAN___API_TOKEN__JWT__SECRET" : + # Prepend 'string:' to the API token secret + prepended_apitoken = "string:" + passwords['CKAN___API_TOKEN__JWT__SECRET'] + f.write(f"CKAN___API_TOKEN__JWT__ENCODE__SECRET={prepended_apitoken}\n") + os.environ['CKAN___API_TOKEN__JWT__ENCODE__SECRET'] = prepended_apitoken + f.write(f"CKAN___API_TOKEN__JWT__DECODE__SECRET={prepended_apitoken}\n") + os.environ['CKAN___API_TOKEN__JWT__DECODE__SECRET'] = prepended_apitoken + else: + f.write(f"{variable}={password}\n") + os.environ[variable] = password + print(f"[generate_passwords] Passwords written to '{filename}' successfully.") + except Exception as e: + logging.error(f"Failed to write passwords to '{filename}': {str(e)}") + +def write_urls_to_file(filename): + try: + with open(filename, 'a') as f: + CKAN_DB_USER = os.environ.get('CKAN_DB_USER') + CKAN_DB_PASSWORD = os.environ.get('CKAN_DB_PASSWORD') + CKAN_DB = os.environ.get('CKAN_DB') + DATASTORE_READONLY_USER = os.environ.get('DATASTORE_READONLY_USER') + DATASTORE_READONLY_PASSWORD = os.environ.get('DATASTORE_READONLY_PASSWORD') + DATASTORE_DB = os.environ.get('DATASTORE_DB') + POSTGRES_HOST = os.environ.get('POSTGRES_HOST') + 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(f"[generate_passwords] Database URL's written to '{filename}' successfully.") + except Exception as e: + logging.error(f"Failed to write database URL's to '{filename}': {str(e)}") + +def main(): + pwvars = [ + "POSTGRES_PASSWORD", + "CKAN_DB_PASSWORD", + "DATASTORE_READONLY_PASSWORD", + "CKAN_SYSADMIN_PASSWORD", + "CKAN___BEAKER__SESSION__SECRET", + "CKAN___API_TOKEN__JWT__SECRET", + ] + + vn = generate_passwords(pwvars) + + # Write database passwords to .dbpw + db_passwords = [ + "POSTGRES_PASSWORD", + "CKAN_DB_PASSWORD", + "DATASTORE_READONLY_PASSWORD", + ] + write_passwords_to_file({variable: vn[variable] for variable in db_passwords}, ".dbpw") + + # Write CKAN passwords to .ckpw + ck_passwords = [ + "CKAN_DB_PASSWORD", + "DATASTORE_READONLY_PASSWORD", + "CKAN_SYSADMIN_PASSWORD", + "CKAN___BEAKER__SESSION__SECRET", + "CKAN___API_TOKEN__JWT__SECRET", + ] + write_passwords_to_file({variable: vn[variable] for variable in ck_passwords}, ".ckpw") + + write_urls_to_file(".ckpw") + + print("\nThe CKAN_SYSADMIN_PASSWORD password is: " + vn['CKAN_SYSADMIN_PASSWORD'] + "\n") + + # Rest of your code + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + main() \ No newline at end of file diff --git a/generate_passwords.sh b/generate_passwords.sh new file mode 100755 index 00000000..6abfe49a --- /dev/null +++ b/generate_passwords.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +set -a +. ./.env +pwfile=".ckpw" +dbpwfile=".dbpw" +touch ${pwfile} && touch ${dbpwfile} +chmod 600 ${pwfile} && chmod 600 ${dbpwfile} +python3 ./generate_passwords.py +chmod 400 ${pwfile} && chmod 400 ${dbpwfile} +sleep 1 \ No newline at end of file diff --git a/postgresql/docker-entrypoint-initdb.d/30_setup_test_databases.sql b/postgresql/docker-entrypoint-initdb.d/30_setup_test_databases.sh similarity index 100% rename from postgresql/docker-entrypoint-initdb.d/30_setup_test_databases.sql rename to postgresql/docker-entrypoint-initdb.d/30_setup_test_databases.sh