diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..404a2d1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +.github/ +docker-compose.yml +LICENSE +Mkaefile +pipepper +README.md +secretkey diff --git a/Dockerfile b/Dockerfile index e3de4b7..0f458c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,6 @@ FROM nginx:1.21 -LABEL maintainer="michimau " -#forked from https://github.com/Khalibre/privacyidea-docker -#original maintainer="Sida Say " +LABEL maintainer="Sida Say " RUN set -xe; \ apt-get -y update && \ @@ -17,29 +15,31 @@ RUN set -xe; \ RUN mkdir -p mkdir /etc/privacyidea/data/keys \ /opt/privacyidea \ /var/log/privacyidea && \ - useradd -r -M -d /opt/privacyidea privacyidea && \ + adduser --gecos "PrivacyIdea User" --disabled-password --home /home/privacyidea privacyidea --uid 1001 && \ + addgroup privacyidea privacyidea && \ + usermod -g 1001 privacyidea && \ chown -R privacyidea:privacyidea /opt/privacyidea /etc/privacyidea /var/log/privacyidea # apt-get remove --purge --auto-remove -y ca-certificates && rm -rf /var/lib/apt/lists/* # COPY PI configuration -COPY ./configs/config.py /etc/privacyidea/pi.cfg +COPY --chown=privacyidea:privacyidea ./configs/config.py /etc/privacyidea/pi.cfg # Remove default configuration from Nginx RUN rm /etc/nginx/conf.d/default.conf # Copy the base uWSGI ini file to enable default dynamic uwsgi process number -COPY ./configs/uwsgi.ini /etc/uwsgi/ +COPY --chown=privacyidea:privacyidea ./configs/uwsgi.ini /etc/uwsgi/ # Custom Supervisord config -COPY ./configs/supervisord-debian.conf /etc/supervisor/supervisord.conf +COPY --chown=privacyidea:privacyidea ./configs/supervisord-debian.conf /etc/supervisor/supervisord.conf # Add demo app -COPY ./configs/app /app +COPY --chown=privacyidea:privacyidea ./configs/app /app -COPY ["configs/start.sh", "configs/entrypoint.sh", "/"] +COPY scripts/* /usr/local/bin/ -RUN chmod +x /entrypoint.sh /start.sh \ +RUN chmod +x /usr/local/bin/*.sh \ && apt-get clean autoclean \ && apt-get autoremove --yes \ && rm -rf /var/lib/{apt,dpkg,cache,log}/ \ @@ -75,7 +75,8 @@ ENV LISTEN_PORT 80 ENV PI_SKIP_BOOTSTRAP=false \ DB_VENDOR=sqlite \ - PI_VERSION=3.6.3 + PI_VERSION=3.7 \ + PI_HOME=/opt/privacyidea ENV VIRTUAL_ENV=/opt/privacyidea RUN python3 -m venv $VIRTUAL_ENV @@ -93,12 +94,8 @@ RUN pip install wheel && \ EXPOSE 80/tcp EXPOSE 443/tcp -#USER privacyidea -ENTRYPOINT ["/entrypoint.sh"] +#USER privacyidea +ENTRYPOINT ["/usr/local/bin/privacyidea_entrypoint.sh"] WORKDIR /app VOLUME [ "/data/privacyidea" ] - -# Run the start script, it will check for an /app/prestart.sh script (e.g. for migrations) -# And then will start Supervisor, which in turn will start Nginx and uWSGI -CMD ["/start.sh"] diff --git a/Makefile b/Makefile index b88d3e7..29f6aa0 100644 --- a/Makefile +++ b/Makefile @@ -5,17 +5,15 @@ info: LOCAL_DATA_VOLUME=/tmp/privacyidea-data build: - docker build -t michimau/privacyidea . + docker build -t khalibre/privacyidea:dev . push: docker push michimau/privacyidea -run: $(LOCAL_DATA_VOLUME) secretkey pipepper - #docker run -v $(LOCAL_DATA_VOLUME):/data/privacyidea -p 80:80 -ti --env-file=secretkey --env-file=pipepper michimau/privacyidea - docker run -p 80:80 -ti --env-file=secretkey --env-file=pipepper michimau/privacyidea +run: cleanup create_volume secretkey pipepper + docker run -v $(LOCAL_DATA_VOLUME):/data/privacyidea -p 80:80 -ti --name=privacyidea-dev --env-file=secretkey --env-file=pipepper khalibre/privacyidea:dev - -$(LOCAL_DATA_VOLUME): +create_volume: mkdir $(LOCAL_DATA_VOLUME) secretkey: @@ -25,3 +23,8 @@ secretkey: pipepper: @echo Creating pipepper @echo PI_PEPPER=$(shell cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1) > pipepper + +cleanup: + docker stop privacyidea-dev || true + docker rm privacyidea-dev || true + sudo rm -rf $(LOCAL_DATA_VOLUME) diff --git a/README.md b/README.md index 27a828b..43e9a19 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # PrivacyIdea Docker Image -This is a build environment to build a docker image for privacyIDEA. +This is a build environment to build a docker image for privacyIDEA base on [official NGINX image](https://hub.docker.com/_/nginx) and [PrivacyIDEA](https://github.com/privacyidea/privacyidea) ## The image -The docker image is a self contained Ubuntu 20.04 with privacyIDEA installed, which will run on every distribution. +The docker image is a self contained Debain with privacyIDEA installed, which will run on every distribution. ## Building @@ -18,31 +18,131 @@ make build Run it with ```bash -make runserver +make run ``` -This will download the existing privacyIDEA container from the Docker hub https://registry.hub.docker.com/u/khalibre/pricvacy/ and run it. - -Login to http://localhost:5000 with "admin"/"privacyidea". +Login to http://localhost with "admin"/"privacyidea". > You must not use this in productive environment, since it contains fixed credentail, encryption keys! -## Advanced usage - -### PrivacyIdea Environment variables - -- CACHE_TYPE -- PI_PEPPER -- PI_AUDIT_KEY_PRIVATE -- PI_AUDIT_KEY_PUBLIC -- PI_AUDIT_MODULE -- PI_ENCFILE -- PI_EXTERNAL_LINKS -- PI_HSM -- PI_LOGFILE -- PI_LOGLEVEL -- SECRET_KEY -- PI_ADMIN_USER -- PI_ADMIN_PASSWORD - -Inspired by https://github.com/tiangolo/uwsgi-nginx-docker +## Configuration + +### Admin credentails + +The Khalibre privacyIDEA container can create a default admin user by setting the following environment variables: + + - `PI_ADMIN_USER`: Administrator default user. Default: **admin**. + - `PI_ADMIN_PASSWORD`: Administrator default password. Default: **privacyidea** + +### Connecting to database + +The Khalibre privacyIDEA requires a database to work. This is configured with the following environment variables: + + - `DB_VENDOR`: Database vendor (support mysql or posgresql) No defaults. + - `DB_USER`: Database user. No defaults. + - `DB_PASSWORD`: Database. No defaults. + - `DB_NAME`: Database name. No defaults. + - `DB_HOST`: Database host. No defaults. + +### NGINX configuration + + - `USE_NGINX_MAX_UPLOAD`: Get the maximum upload file size for Nginx, default to 0: unlimited + - `USE_NGINX_WORKER_PROCESSES`: Get the number of workers for Nginx, default to 1 + - `NGINX_WORKER_CONNECTIONS`: Set the max number of connections per worker for Nginx, if requested. Cannot exceed worker_rlimit_nofile, see NGINX_WORKER_OPEN_FILES below + - `NGINX_SERVER_TOKENS`: Hide Nginx server version on error pages and in the “Server HTTP” response header field + - `USE_LISTEN_PORT`: Get the listen port for Nginx, default to 80 + +### privacyIDEA configuration + + - `CACHE_TYPE`: privacyIDEA cache type. Default simple. + - `PI_PEPPER`: This is used to encrypt the admin passwords. No defaults. + - `PI_AUDIT_KEY_PRIVATE`: This is used to sign the audit log + - `PI_AUDIT_KEY_PUBLIC`: This is used to sign the audit log + - `PI_ENCFILE`: This is used to encrypt the token data and token passwords. No defaults. + - `PI_HSM`: privacyIDEA HSM. Default **default** + - `PI_LOGFILE`: privacyIDEA log file location. Default **/var/log/privacyidea/privacyidea.log** + - `PI_LOGLEVEL`: privacyIDEA log level. Default **INFO** + - `SECRET_KEY`: This is used to encrypt the auth_token. No defaults. + - `SUPERUSER_REALM`: The realm, where users are allowed to login as administrators. Default **administrator** + +## Providing Files to the Container + +The privacyIDEA container uses the files you provide to execute the following use cases: + + - Configure PrivacyIDEA with configuration files + - Configure NGINX with configuration files + - Run scripts + +All of the use cases can be triggered on container creation when the container finds files in specific folders within key container folders. + +### Key Container Folders: + + - /mnt/privacyidea + - /user/local/privacyidea/scripts + +The Container Lifecycle and API specifies the scanned subfolders, the phases in which the container scans them, and the actions taken on their files. + +You can provide files to the container in several ways. + +### Ways to Provide Files: + + - [Bind mounts](https://docs.docker.com/storage/bind-mounts/) + - [Volumes](https://docs.docker.com/storage/volumes/) + - [Using docker cp](https://docs.docker.com/engine/reference/commandline/cp/) + +All of the use cases require making files available on container creation. Bind mounts and volumes accomplish this.Applying config files can be accomplished on container creation using bind mounts and volumes, or at run time using docker cp. + +Bind mounts are used in the examples here as they are simpler than volumes for providing files. As you prepare files for mounting to a container, it’s helpful to organize them in a way that’s easiest for you to manage. Bind mounting to Liferay containers, organizing files, and using docker cp are covered here. + +### Bind Mount Format +You can specify any number of bind mounts to a docker run command. Each bind mount follows this format: + +```bash +-v [source path in host]:[destination path in container] +``` + +The bind mount source can be any folder path or file path in the host. The bind mount destination can be any folder path or file path in the container. + +### Scanned Container Folders + +The container scans these folders. + + - /mnt/privacyidea/files (all files and subfolders are scanned) + - /mnt/privacyidea/scripts + - /usr/local/privacyidea/scripts/post-shutdown + - /usr/local/privacyidea/scripts/pre-configure + - /usr/local/privacyidea/scripts/pre-startup + +## Container Lifecycle and API + +At a high level, the container starts Tomcat with Liferay deployed on it. Additionally, however, the container entry point provides an API for executing these use cases: + + - Invoking scripts + - Configuring NGINX and privacyIDEA + +The container provides an API for triggering and configuring these use cases. It executes the use cases in different phases of its lifecycle. + +### Lifecycle + +After you create a container in an environment, the container entry point executes the following lifecycle phases in that environment: + + 1. Pre-configure: Runs user-provided scripts before configuring NGINX and privacyIDEA. + 2. Configure: Prepares for running NGINX and privacyIDEA. + 1. Set Python's runtime environment. + 2. Run user-provided scripts. + 3. Pre-startup: Runs user-provided scripts before starting Tomcat. + 4. NGINX and privacyIDEA startup: Launches privacyIDEA and NGINX using the supervisd script. + 5. Post-shutdown: Runs user-provided scripts after Tomcat stops. + +### API + +The container entry point scans the following container folders for files and uses those files to configure the container, NGINX, and privacyIDEA and to act on privacyIDEA. + + - /mnt/privacyidea + - /user/local/privacyidea/scripts + +The key folders above have subfolders that are designated for specific actions. The subfolders, the actions taken on their files, and associated use cases are listed in lifecycle phase order in the following sections. + +## Contributing + +We'd love for you to contribute to this container. You can request new features by creating an issue, or submit a pull request with your contribution. diff --git a/configs/app/main.py b/configs/app/main.py deleted file mode 100644 index 16e813b..0000000 --- a/configs/app/main.py +++ /dev/null @@ -1,5 +0,0 @@ -import sys -sys.stdout = sys.stderr -from privacyidea.app import create_app -# Now we can select the config file: -application = create_app(config_name="production", config_file="/etc/privacyidea/pi.cfg") diff --git a/configs/app/prestart.sh b/configs/app/prestart.sh deleted file mode 100755 index 777e7c7..0000000 --- a/configs/app/prestart.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -if { [ "${DB_VENDOR}" = "mariadb" ] || [ "${DB_VENDOR}" = "mysql" ]; } then - echo "Using $DB_VENDOR..." - [ -z "$DB_HOST" ] && echo "DB_HOST should be defined" && return 1 - [ -z "$DB_USER" ] && echo "DB_USER should be defined" && return 1 - [ -z "$DB_PASSWORD" ] && echo "DB_PASSWORD should be defined" && return 1 - [ -z "$DB_NAME" ] && echo "DB_NAME should be defined" && return 1 - export SQLALCHEMY_DATABASE_URI=pymysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME} -elif { [ "${DB_VENDOR}" = "postgresql" ]; } then - export SQLALCHEMY_DATABASE_URI=postgresql+pg8000://${DB_USER}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME} -else - echo "DB_VENDOR enviroment varaible is not set. Using default SQLite..." -fi -if [ "${PI_SKIP_BOOTSTRAP}" = false ]; then - if [ ! -f /etc/privacyidea/encfile ]; then - pi-manage create_enckey - fi - if [ ! -d /etc/privacyidea/keys ]; then - mkdir /etc/privacyidea/keys - fi - if [ ! -f /etc/privacyidea/keys/private.pem ]; then - pi-manage create_audit_keys - fi - pi-manage createdb - pi-manage db stamp head -d /opt/privacyidea/lib/privacyidea/migrations/ - #pi-manage db stamp head -d /usr/local/lib/privacyidea/migrations/ - if { [ "${PI_SKIP_BOOTSTRAP}" = false ] && [ -z ${PI_ADMIN_USER} ] && [ -z ${PI_ADMIN_PASSWORD} ]; } then - echo "Create deafult admin user. Not recommented in production. Please set PI_ADMIN_USER and PI_ADMIN_PASSWORD in production enviroment." - pi-manage admin add admin -p privacyidea - else - echo "Create admin user from definded enviroment variables." - pi-manage admin add ${PI_ADMIN_USER} -p ${PI_ADMIN_PASSWORD} - fi -fi diff --git a/configs/app/uwsgi.ini b/configs/app/uwsgi.ini index 5267ae4..ebe61b4 100644 --- a/configs/app/uwsgi.ini +++ b/configs/app/uwsgi.ini @@ -1,3 +1,3 @@ [uwsgi] -wsgi-file=/app/main.py +wsgi-file=/opt/privacyidea/etc/privacyidea/privacyideaapp.wsgi buffer-size=8192 diff --git a/configs/config.py b/configs/config.py index eb73248..5a988d2 100644 --- a/configs/config.py +++ b/configs/config.py @@ -24,9 +24,6 @@ PI_NODE = os.environ.get("HOSTNAME", "localnode") CACHE_TYPE = os.environ.get("CACHE_TYPE", "simple") PI_EXTERNAL_LINKS = os.environ.get("PI_EXTERNAL_LINKS", "True").lower() == "true" -# PI_GNUPG_HOME = "gpg" -# PI_LOGO = "otherlogo.png" -# PI_AUDIT_SQL_URI = sqlite:// PI_VASCO_LIBRARY = None PI_ENGINE_REGISTRY_CLASS = os.environ.get("PI_ENGINE_REGISTRY_CLASS", "shared") PI_PAGE_TITLE = os.environ.get("PI_PAGE_TITLE", "privacyIDEA Authentication System") diff --git a/configs/entrypoint.sh b/configs/entrypoint.sh deleted file mode 100644 index 0fdd679..0000000 --- a/configs/entrypoint.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env sh -set -e - -# Get the maximum upload file size for Nginx, default to 0: unlimited -USE_NGINX_MAX_UPLOAD=${NGINX_MAX_UPLOAD:-0} - -# Get the number of workers for Nginx, default to 1 -USE_NGINX_WORKER_PROCESSES=${NGINX_WORKER_PROCESSES:-1} - -# Set the max number of connections per worker for Nginx, if requested -# Cannot exceed worker_rlimit_nofile, see NGINX_WORKER_OPEN_FILES below -NGINX_WORKER_CONNECTIONS=${NGINX_WORKER_CONNECTIONS:-1024} - -# Hide Nginx server version on error pages and in the “Server HTTP” response header field -NGINX_SERVER_TOKENS=${NGINX_SERVER_TOKENS:-off} - -# Get the listen port for Nginx, default to 80 -USE_LISTEN_PORT=${LISTEN_PORT:-80} - -if [ -f /app/nginx.conf ]; then - cp /app/nginx.conf /etc/nginx/nginx.conf -else - content='user nginx;\n' - # Set the number of worker processes in Nginx - content=$content"worker_processes ${USE_NGINX_WORKER_PROCESSES};\n" - content=$content'error_log /var/log/nginx/error.log warn;\n' - content=$content'pid /var/run/nginx.pid;\n' - content=$content'events {\n' - content=$content" worker_connections ${NGINX_WORKER_CONNECTIONS};\n" - content=$content'}\n' - content=$content'http {\n' - content=$content' include /etc/nginx/mime.types;\n' - content=$content' default_type application/octet-stream;\n' - content=$content' log_format main '"'\$remote_addr - \$remote_user [\$time_local] \"\$request\" '\n" - content=$content' '"'\$status \$body_bytes_sent \"\$http_referer\" '\n" - content=$content' '"'\"\$http_user_agent\" \"\$http_x_forwarded_for\"';\n" - content=$content' access_log /var/log/nginx/access.log main;\n' - content=$content' sendfile on;\n' - content=$content' keepalive_timeout 65;\n' - content=$content" server_tokens ${NGINX_SERVER_TOKENS};\n" - content=$content' include /etc/nginx/conf.d/*.conf;\n' - content=$content'}\n' - content=$content'daemon off;\n' - # Set the max number of open file descriptors for Nginx workers, if requested - if [ -n "${NGINX_WORKER_OPEN_FILES}" ] ; then - content=$content"worker_rlimit_nofile ${NGINX_WORKER_OPEN_FILES};\n" - fi - # Save generated /etc/nginx/nginx.conf - printf "$content" > /etc/nginx/nginx.conf - - content_server='server {\n' - content_server=$content_server" listen ${USE_LISTEN_PORT};\n" - content_server=$content_server' location / {\n' - content_server=$content_server' include uwsgi_params;\n' - content_server=$content_server' uwsgi_pass unix:///tmp/uwsgi.sock;\n' - content_server=$content_server' }\n' - content_server=$content_server'}\n' - # Save generated server /etc/nginx/conf.d/nginx.conf - printf "$content_server" > /etc/nginx/conf.d/nginx.conf - - # Generate Nginx config for maximum upload file size - printf "client_max_body_size $USE_NGINX_MAX_UPLOAD;\n" > /etc/nginx/conf.d/upload.conf - - # Remove default Nginx config from Alpine - printf "" > /etc/nginx/conf.d/default.conf -fi - -# For Alpine: -# Explicitly add installed Python packages and uWSGI Python packages to PYTHONPATH -# Otherwise uWSGI can't import Flask -if [ -n "$ALPINEPYTHON" ] ; then - export PYTHONPATH=$PYTHONPATH:/usr/local/lib/$ALPINEPYTHON/site-packages:/usr/lib/$ALPINEPYTHON/site-packages -fi -exec "$@" diff --git a/configs/start.sh b/configs/start.sh deleted file mode 100644 index ced93ce..0000000 --- a/configs/start.sh +++ /dev/null @@ -1,16 +0,0 @@ -#! /usr/bin/env sh -set -e - -# If there's a prestart.sh script in the /app directory, run it before starting -PRE_START_PATH=/app/prestart.sh -echo "Checking for script in $PRE_START_PATH" -if [ -f $PRE_START_PATH ] ; then - echo "Running script $PRE_START_PATH" - . $PRE_START_PATH -else - echo "There is no script $PRE_START_PATH" -fi - -# Start Supervisor, with Nginx and uWSGI -#exec /usr/local/bin/supervisord -exec /usr/bin/supervisord diff --git a/configs/supervisord-debian.conf b/configs/supervisord-debian.conf index 236e8bc..5042084 100644 --- a/configs/supervisord-debian.conf +++ b/configs/supervisord-debian.conf @@ -1,9 +1,9 @@ [supervisord] nodaemon=true +user=root [program:uwsgi] command=/opt/privacyidea/bin/uwsgi --ini /etc/uwsgi/uwsgi.ini -#command=/usr/local/bin/uwsgi --ini /etc/uwsgi/uwsgi.ini stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr diff --git a/configs/uwsgi.ini b/configs/uwsgi.ini index e222c37..55e15d2 100644 --- a/configs/uwsgi.ini +++ b/configs/uwsgi.ini @@ -7,7 +7,7 @@ hook-master-start = unix_signal:15 gracefully_kill_them_all need-app = true die-on-term = true # For debugging and testing -show-config = true +show-config = false # enable thread disable-logging = true enable-threads = true diff --git a/scripts/_privacyidea_common.sh b/scripts/_privacyidea_common.sh new file mode 100755 index 0000000..79d8a8e --- /dev/null +++ b/scripts/_privacyidea_common.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +function execute_scripts { + if [ -e "${1}" ] && [[ $(find "${1}" -maxdepth 1 -name "*.sh" -printf "%f\n") ]] + then + echo "[PrivacyIDEA] Executing scripts in ${1}:" + + for SCRIPT_NAME in $(find "${1}" -maxdepth 1 -name "*.sh" -printf "%f\n" | sort) + do + echo "" + echo "[PrivacyIDEA] Executing ${SCRIPT_NAME}." + + source "${1}/${SCRIPT_NAME}" + done + + echo "" + fi +} diff --git a/scripts/configure_nginx.sh b/scripts/configure_nginx.sh new file mode 100644 index 0000000..7524198 --- /dev/null +++ b/scripts/configure_nginx.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +set -e + +function main { + # Get the maximum upload file size for Nginx, default to 0: unlimited + USE_NGINX_MAX_UPLOAD=${NGINX_MAX_UPLOAD:-0} + + # Get the number of workers for Nginx, default to 1 + USE_NGINX_WORKER_PROCESSES=${NGINX_WORKER_PROCESSES:-1} + + # Set the max number of connections per worker for Nginx, if requested + # Cannot exceed worker_rlimit_nofile, see NGINX_WORKER_OPEN_FILES below + NGINX_WORKER_CONNECTIONS=${NGINX_WORKER_CONNECTIONS:-1024} + + # Hide Nginx server version on error pages and in the “Server HTTP” response header field + NGINX_SERVER_TOKENS=${NGINX_SERVER_TOKENS:-off} + + # Get the listen port for Nginx, default to 80 + USE_LISTEN_PORT=${LISTEN_PORT:-80} + + if [ -f /app/nginx.conf ]; then + cp /app/nginx.conf /etc/nginx/nginx.conf + else + content='user nginx;\n' + # Set the number of worker processes in Nginx + content=$content"worker_processes ${USE_NGINX_WORKER_PROCESSES};\n" + content=$content'error_log /var/log/nginx/error.log warn;\n' + content=$content'pid /var/run/nginx.pid;\n' + content=$content'events {\n' + content=$content" worker_connections ${NGINX_WORKER_CONNECTIONS};\n" + content=$content'}\n' + content=$content'http {\n' + content=$content' include /etc/nginx/mime.types;\n' + content=$content' default_type application/octet-stream;\n' + content=$content' log_format main '"'\$remote_addr - \$remote_user [\$time_local] \"\$request\" '\n" + content=$content' '"'\$status \$body_bytes_sent \"\$http_referer\" '\n" + content=$content' '"'\"\$http_user_agent\" \"\$http_x_forwarded_for\"';\n" + content=$content' access_log /var/log/nginx/access.log main;\n' + content=$content' sendfile on;\n' + content=$content' keepalive_timeout 65;\n' + content=$content" server_tokens ${NGINX_SERVER_TOKENS};\n" + content=$content' include /etc/nginx/conf.d/*.conf;\n' + content=$content'}\n' + content=$content'daemon off;\n' + # Set the max number of open file descriptors for Nginx workers, if requested + if [ -n "${NGINX_WORKER_OPEN_FILES}" ] ; then + content=$content"worker_rlimit_nofile ${NGINX_WORKER_OPEN_FILES};\n" + fi + # Save generated /etc/nginx/nginx.conf + printf "$content" > /etc/nginx/nginx.conf + + content_server='server {\n' + content_server=$content_server" listen ${USE_LISTEN_PORT};\n" + content_server=$content_server' location / {\n' + content_server=$content_server' include uwsgi_params;\n' + content_server=$content_server' uwsgi_pass unix:///tmp/uwsgi.sock;\n' + content_server=$content_server' }\n' + content_server=$content_server'}\n' + # Save generated server /etc/nginx/conf.d/nginx.conf + printf "$content_server" > /etc/nginx/conf.d/nginx.conf + + # Generate Nginx config for maximum upload file size + printf "client_max_body_size $USE_NGINX_MAX_UPLOAD;\n" > /etc/nginx/conf.d/upload.conf + + # Remove default Nginx config from Alpine + printf "" > /etc/nginx/conf.d/default.conf + fi +} + +main diff --git a/scripts/privacyidea_entrypoint.sh b/scripts/privacyidea_entrypoint.sh new file mode 100644 index 0000000..2f82f6d --- /dev/null +++ b/scripts/privacyidea_entrypoint.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +source /usr/local/bin/_privacyidea_common.sh + +function main { + echo "[PrivacyIDEA] To SSH into this container, run: \"docker exec -it ${HOSTNAME} /bin/bash\"." + echo "" + + if [ -d /etc/privacyidea/mount ] + then + PI_MOUNT_DIR=/etc/privacyidea/mount + else + PI_MOUNT_DIR=/mnt/privacyidea + fi + + export PI_MOUNT_DIR + + execute_scripts /usr/local/privacyidea/scripts/pre-configure + + . configure_nginx.sh + + execute_scripts /usr/local/privacyidea/scripts/pre-startup + + start_privacyidea + + execute_scripts /usr/local/privacyidea/scripts/post-shutdown +} + +function start_privacyidea { + . start_privacyidea.sh +} + +main diff --git a/scripts/start_privacyidea.sh b/scripts/start_privacyidea.sh new file mode 100644 index 0000000..f3750b2 --- /dev/null +++ b/scripts/start_privacyidea.sh @@ -0,0 +1,80 @@ +#!/bin/bash +set -e + +source /usr/local/bin/_privacyidea_common.sh + +function main { + echo "" + echo "[PrivacyIDEA] Starting ${PrivacyIDEA}. To stop the container with CTRL-C, run this container with the option \"-it\"." + echo "" + + prestart_privacyidea + exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf +} + +function prestart_privacyidea { + if [ -d "${PI_MOUNT_DIR}"/files ] + then + if [[ $(ls -A "${PI_MOUNT_DIR}"/files) ]] + then + echo "[privacyIDEA] Copying files from ${PI_MOUNT_DIR}/files:" + echo "" + + tree --noreport "${PI_MOUNT_DIR}"/files + + echo "" + echo "[privacyIDEA] ... into ${PI_HOME}." + + cp -r "${PI_MOUNT_DIR}"/files/* "${PI_HOME}" + + echo "" + fi + else + echo "[privacyIDEA] The directory /mnt/konakart/files does not exist. Create the directory \$(pwd)/xyz123/files on the host operating system to create the directory ${PI_MOUNT_DIR}/files on the container. Files in ${PI_MOUNT_DIR}/files will be copied to ${PI_HOME} before privacyIDEA starts." + echo "" + fi + + if [ -d "${PI_MOUNT_DIR}"/scripts ] + then + execute_scripts "${PI_MOUNT_DIR}"/scripts + else + echo "[privacyIDEA] The directory /mnt/konakart/scripts does not exist. Create the directory \$(pwd)/xyz123/scripts on the host operating system to create the directory ${PI_MOUNT_DIR}/scripts on the container. Files in ${PI_MOUNT_DIR}/scripts will be executed, in alphabetical order, before privacyIDEA starts." + echo "" + fi + + if { [ "${DB_VENDOR}" = "mariadb" ] || [ "${DB_VENDOR}" = "mysql" ]; } then + echo "Using $DB_VENDOR..." + [ -z "$DB_HOST" ] && echo "DB_HOST should be defined" && return 1 + [ -z "$DB_USER" ] && echo "DB_USER should be defined" && return 1 + [ -z "$DB_PASSWORD" ] && echo "DB_PASSWORD should be defined" && return 1 + [ -z "$DB_NAME" ] && echo "DB_NAME should be defined" && return 1 + export SQLALCHEMY_DATABASE_URI=pymysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME} + elif { [ "${DB_VENDOR}" = "postgresql" ]; } then + export SQLALCHEMY_DATABASE_URI=postgresql+pg8000://${DB_USER}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME} + else + echo "DB_VENDOR enviroment varaible is not set. Using default SQLite..." + fi + if [ "${PI_SKIP_BOOTSTRAP}" = false ]; then + if [ ! -f /etc/privacyidea/encfile ]; then + pi-manage create_enckey + fi + if [ ! -d /etc/privacyidea/keys ]; then + mkdir /etc/privacyidea/keys + fi + if [ ! -f /etc/privacyidea/keys/private.pem ]; then + pi-manage create_audit_keys + fi + pi-manage createdb + pi-manage db stamp head -d /opt/privacyidea/lib/privacyidea/migrations/ + #pi-manage db stamp head -d /usr/local/lib/privacyidea/migrations/ + if { [ "${PI_SKIP_BOOTSTRAP}" = false ] && [ -z ${PI_ADMIN_USER} ] && [ -z ${PI_ADMIN_PASSWORD} ]; } then + echo "Create deafult admin user. Not recommented in production. Please set PI_ADMIN_USER and PI_ADMIN_PASSWORD in production enviroment." + pi-manage admin add admin -p privacyidea + else + echo "Create admin user from definded enviroment variables." + pi-manage admin add ${PI_ADMIN_USER} -p ${PI_ADMIN_PASSWORD} + fi + fi +} + +main