Simply deploy and run a privacyIDEA instance in a container environment.
privacyIDEA is an open solution for strong two-factor authentication like OTP tokens, SMS, smartphones or SSH keys.
This project is a complete build environment under linux to build and run privacyIDEA in a container environment. It uses the official python image and the official privacyIDEA-Project from PyPi. The image uses gunicorn to run the app.
The main goals of this project are to:
- Give an idea how to run privacyIDEA in a container.
- Build and run the container image, simple and fast.
- Deploy different versions and/or stages (e.g. production, staging, devel ...) with the same or different configuration on the same host.
- Easy deploy a "full-stack" (e.g. privacyIDEA, radius, database and reverse proxy) with docker compose.
- Keep the container's image simple and slim.
- Build images with no changes to the original privacyIDEA code and few additional scripts as possible inside the image to run the container.
What this project is not:
- A fully tested and "production-ready" installation of privacyIDEA for your container environment.
- A possible way to ignore the privacyIDEA Documentation
- A guide on how to use docker
- The "one and only" or "best" method to run privacyIDEA in a container.
- Finished ;)
Note
The image does not include a reverse proxy or a database backend. Running the default image as a standalone container uses gunicorn and a sqlite database. This is not suitable for a production environment.
A more 'real-world' scenario, which is often used, is described in the Compose a privacyIDEA stack section.
Also check the Security considerations before running the image or stack in a production environment.
While decoupling the privacyIDEA image from dependencies like Nginx, Apache or database vendors, it is possible to run privacyIDEA with your favorite components.
If you prefer another approach or would like to test another solution, take a look at the Khalibre / privacyidea-docker project. This project might be a more suitable solution for your needs.
Clone repository and start a full privacyIDEA stack:
git clone https://github.com/gpappsoft/privacyidea-docker.git
cd privacyidea-docker
make cert secret fullstack
Directory | Description |
---|---|
conf | contains pi.cfg and logging.cfg files which is included in the image build process. |
secrets | contains the secrets for docker compose - this project tries to avoid using env-vars for sensitive data (passwords) |
scripts | contains custom scripts for the script-handler. Will be mounted into the container when compose a stack. Scripts must be executable (chmod +x) |
environment | contains different example-environment files for a whole stack via docker compose |
ssl | contains ssl certificates for the reverse-proxy. Replace it with your own certificate and key file. Use PEM-Format without a passphrase. *.pfx is not supported. Name must be pi.pem and pi.key |
templates | contains files used for different services (nginx, radius ...) |
Sample images from this project can be found here:
registry | repository |
---|---|
docker.io | docker pull docker.io/gpappsoft/privacyidea-docker:latest |
ghcr.io | docker pull ghcr.io/gpappsoft/privacyidea-docker:latest |
Note
latest
tagged image is maybe a pre- or development-release. Please use always a release number (like 3.9.3
)
- Installed a container runtime engine (docker / podman).
- Installed BuildKit, buildx and Compose V2 (docker-compose-v2) components
- The repository is tested with versions listed in COMPAT.md
- Podman is partially supported. Please refer to PODMAN.md for more details.
docker pull docker.io/gpappsoft/privacyidea-docker:3.9.3
docker run -d --name privacyidea-docker\
-e PI_REGISTRY_CLASS=null\
-e DB_PASSWORD=null\
-e PI_BOOTSTRAP=true\
-e PI_PEPPER=null\
-e PI_SECRET=null\
-v pi-pilog:/var/log/privacyidea:rw,Z\
-v pi-piconfig:/etc/privacyidea:rw,Z\
-p 8080:8080\
gpappsoft/privacyidea-docker:3.9.3
Web-UI: http://localhost:8080
user/password: admin / admin
To build and run a simple local privacyIDEA container (which can run standalone with sqlite):
git clone https://github.com/gpappsoft/privacyidea-docker.git
cd privacyidea-docker
make cert secret build run
....
Answer the following question with a y
:
Warning! Overwrite ALL SECRETS in ./secrets directory: Are you sure? [y/N] y
Default admin username: admin
Default admin password is stored in ./secrets/pi_admin_pass
You can use Makefile targets to build different images with different privacyIDEA versions.
make build PI_VERSION=3.8.1
Use make push [REGISTRY=<registry>]
to tag and push the image1
Push image to local registry on port 50002
make push REGISTRY=localhost:5000
make clean
You can start the container with the same database (sqlite) and configuration and use make run
again without bootstrapping the instance.
make distclean
ⓘ This will wipe the whole container including the volumes!
target | optional ARGS | description | example |
---|---|---|---|
build |
PI_VERSION IMAGE_NAME |
Build an image. Optional: specify the version and image name | make build PI_VERSION=3.9.3 |
push |
REGISTRY |
Tag and push the image to the registry. Optional: specify the registry URI. Defaults to localhost:5000 | make push REGISTRY=docker.io/gpappsoft/privacyidea-docker |
run |
PORT TAG |
Run a standalone container with gunicorn and sqlite. Optional: specify the prefix tag of the container name and listen port. Defaults to pi and port 8080 | make run TAG=prod PORT=8888 |
secret |
Generate and overwrite secrets in ./secrets | make secret |
|
cert |
Generate a self-signed certificate for the reverse proxy container in ./ssl. and overwrite the existing one | make secret |
|
stack |
TAG PROFILE |
Run a whole stack with the environment file environment/application-TAG .env. Default is prod. Possible PROFILE values: stack,fullstack,ldap,radius |
make stack , make stack TAG=dev PROFILE=fullstack , make stack TAG=prod PROFILE=stack,radius |
clean |
TAG |
Remove the container and network without removing the named volumes. Optional: change prefix tag of the container name. Defaults to pi | make clean TAG=prod |
distclean |
TAG |
Remove the container, network and named volumes. Optional: change prefix tag of the container name. Defaults to pi | make distclean TAG=prod |
Important
Using the image as a standalone container is not production ready. For a more like 'production ready' instance, please refer to the next section.
By using docker compose you can easily deploy a customized privacyIDEA instance, including Nginx as a reverse-proxy and MariaDB as a database backend.
With the use of different environment files for different full-stacks, you can deploy and run multiple stacks at the same time on different ports.
graph TD;
a2("--env-file=environment/application-dev.env");
w4(https://localhost:8444);
w5(RADIUS 2812);
w6(LDAP 2389);
subgraph s3 [ ];
r2(RADIUS);
n5(NGINX);
n6(LDAP);
n7(privacyIDEA);
n8(MariaDB);
st2[stack 2];
end;
a1("--env-file=environment/application-prod.env");
w1(https://localhost:8443);
w2(RADIUS 1812);
w3(LDAP 1389);
subgraph s1 [ ];
r1(RADIUS);
n1(NGINX);
n2(LDAP);
n3(privacyIDEA);
n4(MariaDB);
st1[Stack 1];
end;
a1~~~w1;
a1~~~w2;
a1~~~w3;
a2~~~w4;
a2~~~w5;
a2~~~w6;
w1<-- API / WebUI -->n1<-- reverse proxy -->n3(privacyIDEA)<-->n4
w2<-- radius auth -->r1<-- privacyIDEA Radius -->n3
w3<-- for clients -->n2<-- resolver -->n3
w4<-- API / WebUI -->n5<-- reverse proxy -->n7(privacyIDEA)<-->n8
w5<-- radius auth -->r2<-- privacyIDEA Radius -->n7
w6<-- for clients -->n6<-- resolver -->n7
classDef plain font-size:12px,fill:#ddd,stroke:#fff,stroke-width:4px,color:#000;
classDef heading font-size:12px,fill:#9db668,stroke:#fff,stroke-width:1px,color:#fff;
classDef title font-size:16px,color:#000,background-color:#9db668,stroke:#ffff;
classDef docker fill:#265a88,stroke:#fff,stroke-width:2px,color:#fff;
classDef second fill:#dba614,stroke:#fff,stroke-width:2px,color:#fff;
classDef tags fill:#dba614,stroke:#fff,stroke-width:2px,color:#fff;
classDef cluster fill:#fff,stroke:#888,stroke-width:2px,color:#265a88;
class w1,w2,w3,w4,w5,w6 plain;
class r1,n2,r2,n6 second;
class n1,n3,n4,n5,n6,n7,n8,r2,t1 docker;
class s1,s2,s3,s4 title;
class a1,a2,st1,st2 heading;
Find example .env files in the environment directory.
Note
The optional RADIUS and LDAP container is only available with PROFILE=fullstack|ldap|radius
. See examples below.
- The radius container use the image from privacyidea-freeradius.
- The openldap use the osicia/docker-openldap image.
Note
The docker-compose.yaml, used in this example, always use images from external registries. Change docker-compose.yaml to use your own images.
Run a stack with project the name prod and environment variables files from environment/application-prod.env
$ make cert secret #run only once to generate certificate and secrets
$ PI_BOOTSTRAP=true docker compose --env-file=environment/application-prod.env -p prod up
Or simple run a make
target.
This example will start a stack including privacyIDEA, reverse_proxy and mariadb container:
make cert secret stack
This example will start a full stack including privacyIDEA, reverse_proxy, mariadb, ldap and radius. Project tag is prod
make cert secret stack PROFILE=fullstack TAG=prod
Note
The ldap have sample users. The resolvers and realm are already configured in privacyIDEA when stack is ready.
Shutdown the stack with the project name prod and remove all resources (container,networks, etc.) except the volumes.
docker compose -p prod down
You can start the stack in the background with console detached using the -d parameter.
$ PI_BOOTSTRAP=true docker compose --env-file=environment/application-prod.env -p prod up -d
Full example including build with make
targets:
make cert secret build push stack PI_VERSION=3.9.3 TAG=pidev
Now you can deploy additional containers like OpenLDAP for user realms or Owncloud as a client to test 2FA authentication.
Have fun!
Important
- Volumes will not be deleted.
- Currently same secrets from ./secrets/ are used for every stack. Future releases will change this behavior.
- Delete the /etc/privacyidea/BOOTSTRAP file *inside the privacyIDEA container if you want to bootstrap again. This will not delete an existing database!
- Compose takes some additional time (~1 minute) because of health-checks.
Variable | Default | Description |
---|---|---|
ENVIRONMENT |
environment/application-prod.env | Used to set the correct environment file (env_file) in the docker compose, which is used by the container. Use a relative filename here. |
PI_VERSION |
3.9.3 | Set the used image version |
PI_BOOTSTRAP |
false | Set to true to create database tables on the first start of the container. If you need to re-run, then you have to delete the /etc/privacyidea/BOOTSTRAP file inside the container. |
PI_UPDATE |
false | Set to true to run the database schema upgrade script in case of a new privacyIDEA version. |
PI_PASSWORD |
admin | Don't use this in productive environments. Use secrets with docker compose / docker swarm instead. See Security considerations for more information. |
PI_ADMIN |
admin | login name of the initial administrator |
PI_PORT |
8080 | Port used by gunicorn. Don't use this directly in productive environments. Use a reverse proxy.. |
PI_LOGLEVEL |
INFO | Log level in uppercase (DEBUG, INFO, WARNING, ect.). docker log is always INFO level because of security. See conf/logging.cfg for more details |
SUPERUSER_REALM |
"admin,helpdesk" | Admin realms, which can be used for policies in privacyIDEA. Comma separated list. See the privacyIDEA documentation for more information. |
PI_SQLALCHEMY_ENGINE_OPTIONS |
False | Set pool_pre_ping option. Set to True for DB clusters (like Galera). |
PI_PEPPER |
/run/secrets/pi_pepper | Used for PI_PEPPER in pi.cfg. The filename, including the path, to the file inside the container, with the secret. Use make secrets to generate new secret file. See Security considerations for more information. |
SECRET_KEY |
/run/secrets/pi_secret | Used for SECRET_KEY in pi.cfg. The filename, including the path, to the file inside the container, with the secret. Use make secrets to generate new secret file. See Security considerations for more information. |
Variable | Description |
---|---|
DB_HOST |
Database host |
DB_PORT |
Database port |
DB_NAME |
Database name |
DB_USER |
Database user |
DB_PASSWORD |
The filename, including the path, to the file inside the container, with the database password. |
DB_API |
Database driver (e.g. mysql+pymysql ) |
DB_EXTRA_PARAM |
Extra parameter (e.g. "?charset=utf8" ). Will be appended to the SQLAlchemy URI (see pi.cfg) |
Variable | Default | Description |
---|---|---|
PROXY_PORT |
8443 | Exposed HTTPS port |
PROXY_SERVERNAME |
localhost | Set the reverse-proxy server name. Should be the common name used in the certificate. |
Variable | Default | Description |
---|---|---|
RADIUS_PORT |
1812 | Exposed (external) radius port tcp/udp |
RADIUS_PORT |
1813 | Additional exposed (external) radius port udp |
Variable | Default | Description |
---|---|---|
LDAP_PORT |
1389 | Exposed (external) ldap port |
Filename | Default | Description |
---|---|---|
db_password | superSecret | The database password |
pi_admin_pass | admin | The password for the initial admin |
pi_pepper | superSecret | The PI_PEPPER secret for pi.cfg |
pi_secret | superSecret | The SECRET_KEY secret for pi.cfg |
- Openldap admin user:
cn=admin,dc=example,dc=org
with passwordopenldap
- Password for ldap user always givenName in lowercase (e.g. Sandra Bullock = sandra)
- Additional user
helpdesk
with passwordhelpdesk
andadmin
with passwordadmin
available in ldap
The current concept of using secrets with files in docker-compose.yaml is a first approach to reducing the risk of using secrets with environment variables. This may change in future versions.
Different stacks always use the same secrets.
- unkown
- I only included the most essential and often-used parameters. You can add more variables to the conf/pi.conf file and build your own image.
- The image should only contain a bare privacyIDEA without custom data. You can add them to the Dockerfile file and build your own image.
- Simply use a cron job on the host system with docker exec and the pi-manage command:
docker exec -it pi-privacyidea-1 pi-manage audit rotate_audit --age 90
- Use docker log or use the logfile:
docker logs pi-privacyidea-1
docker exec -it pi-privacyidea-1 cat /var/log/privacyidea/privacyidea.log
- Build a new image, make a push and pull. Re-create the container with
PI_UPDATE=true
. This will run the schema update script to update the database.
- Yes, by providing the sql dump to the db container. Please refer to the "Initializing the database contents" section from the official MariaDB docker documentation.
- Check the Prerequisites and requirements. Often there is a missing plugin (buildx, compose) - install the plugins and try again:
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.23.3/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
curl -SL https://github.com/docker/buildx/releases/download/v0.12.0/buildx-v0.12.0.linux-amd64 -o $DOCKER_CONFIG/cli-plugins/docker-buildx
chmod +x $DOCKER_CONFIG/cli-plugins/docker-{buildx,compose}
Check selinux and change the permissions like:
chcon -R -t container_file_t PATHTOHOSTDIR
PATHTOHOSTDIR
should point to the privacyidea-docker folder.
Help! Error response from daemon: invalid mount config for type "bind": bind source path does not exist: ...
, how can I fix it?
Check if the required certificates (pi.key / pi.pem) exists in ssl/
- Maybe you try to use ssl: Use the insecure option in your /etc/containers/registries.conf:
[[registry]] prefix="localhost" location="localhost:5000" insecure=true
- The pi-manage backup command is not working. You have to dump the database manually. For the example stack, use the db container:
docker exec -it pi-db-1 mariadb-dump -u pi -psuperSecret pi
- enckey/config, certificates and logs stored in the named volumes *_piconfig *_pilog
Support for customization comming soon.
A first release of a Freeradius image with the privacyIDEA-RADIUS plugin is in progress.
Any feedback are welcome!
This project is my private project doing in my free time. This project is not from the NetKnights company. The project uses the open-source version of privacyIDEA. There is no official support from NetKnights for this project.