This repository contains a Pluggable Authentication Module (PAM) to allow authentication against a central OIDC provider.
-
Acquire (see the releases page) or build (see below) the appropriate
libpam_oidc.soclib binary for your platform that provides the PAM interface to authenticate via an OIDC provider.- The
libpam_oidc_gnu.sobinary is built for GNU/Linux distributions and dynamically links to the OS's glibc library. - The
libpam_oidc_musl.sobinary is built for GNU/Linux distributions and statically links to the MUSL library. It sacrifices speed for portability. - Use
libpam_oidc_musl.soif you are using thepercona/percona-xtradb-clusterimage (e.g. in the DataJoint Works Percona cluster), since it is based on Alpine Linux.
- The
-
Copy
libpam_oidc.sointo the appropriate directory where your system expects new PAM modules to be loaded. On some distributions of Debian, it is located in/lib/x86_64-linux-gnu/security/, on others it is/usr/lib64/security/.- Use
ldconfig -p | grep pamto find the directory on your distribution.
- Use
-
Create a service config file within the directory that your system expects for PAM. For example, on Debian, it is located in
/etc/pam.d/. We can create a service/file at/etc/pam.d/oidcwith the following contents (note the argument in the 1st line should be the path wherepam_oidc's config will be located):auth sufficient libpam_oidc.so /etc/datajoint/libpam_oidc.yaml account optional libpam_oidc.soSee service_example for more info.
-
In the path provided to the service config, create a config file for
pam_oidc. See libpam_oidc_example.yaml for more info. -
Configure your PAM-compatible application/service to point to the
oidcservice we just created. For example, we can configure Percona MySQL to use PAM. See MySQL testing for an example.
Since v0.1.5, the test and build have been moved to a Docker Compose file.
Since v0.1.5, releases are built in the builder service. See the builder Dockerfile for details. Building with Docker Compose requires a .env file at the repository root (it can be empty). We can build the binaries for targets x86_64-unknown-linux-gnu and x86_64-unknown-linux-musl, respectively:
docker compose up --build builder
mkdir -p pam-oidc/bin
docker compose cp builder:/tmp/pam-oauth2/libpam_oidc_gnu.so ./pam-oidc/bin/
docker compose cp builder:/tmp/pam-oauth2/libpam_oidc_musl.so ./pam-oidc/bin/
docker compose downThere are three types of tests:
- Unit tests
- PAM integration tests
- MySQL tests
Some testing modes use Docker Compose.
The ones that do require a .env file defining environment variables for the percona service:
DJ_AUTH_USER=
DJ_AUTH_PASSWORD=
DJ_AUTH_TOKEN=Unit test development is WIP.
Unit tests are written in Rust and only test the Rust code. They do not test the PAM integration.
Run these tests using cargo test.
These integration tests cover the PAM integration, but none of the services that use PAM such as SSH or MySQL.
In other words, they test all but the last step in the Deploy Instructions.
These tests run the test.py script in the percona service, using the python-pam library to simulate PAM calls.
To run these tests, create the .env file as mentioned previously, then run:
docker compose run --build percona python3 /opt/test.py
# dkc run -it percona python3 /opt/test.py
# [+] Creating 1/0
# ✔ Container pam-oauth2-builder Created 0.0s
# [+] Running 1/1
# ✔ Container pam-oauth2-builder Started 0.4s
# Authenticated (pam_unix)? True
# Reason (pam_unix): Success
# Authenticating with DJ_AUTH_USER='demouser'
# [2024-01-17 03:51:23.334][pam-oidc][0.1.4][INFO][656398155]: Auth detected. Proceeding...
# [2024-01-17 03:51:23.335][pam-oidc][0.1.4][INFO][656398155]: Inputs read.
# [2024-01-17 03:51:23.335][pam-oidc][0.1.4][INFO][656398155]: Check as password.
# [2024-01-17 03:51:23.651][pam-oidc][0.1.4][INFO][656398155]: Verifying token.
# [2024-01-17 03:51:23.896][pam-oidc][0.1.4][INFO][656398155]: Auth success!
# Authenticated (oidc user:pass)? True
# Reason (oidc user:pass): Success
# Authenticating with DJ_AUTH_USER='demouser'
# [2024-01-17 03:51:23.897][pam-oidc][0.1.4][INFO][656398155]: Auth detected. Proceeding...
# [2024-01-17 03:51:23.897][pam-oidc][0.1.4][INFO][656398155]: Inputs read.
# [2024-01-17 03:51:23.897][pam-oidc][0.1.4][INFO][656398155]: Check as token.
# [2024-01-17 03:51:23.897][pam-oidc][0.1.4][INFO][656398155]: Verifying token.
# [2024-01-17 03:51:24.137][pam-oidc][0.1.4][INFO][656398155]: Auth success!
# Authenticated (oidc user:token)? True
# Reason (oidc user:token): SuccessThe test.py script will try authenticating in three ways:
- Using the
pam_unixmodule as userap_user. This checks that PAM is working in general. - Using the
oidcmodule as userDJ_AUTH_USERwith passwordDJ_AUTH_PASSWORD. This checks that thepam_oidcmodule is working with the password flow. - Using the
oidcmodule as userDJ_AUTH_USERwith tokenDJ_AUTH_TOKEN. This checks that thepam_oidcmodule is working with the token flow.
These tests cover the PAM integration with MySQL.
Create the .env file and issue the following commands, replacing demouser with the value of DJ_AUTH_USER in the .env file:
docker compose up --build -d percona
# Wait until service is healthy, then create demouser
docker compose exec percona mysql -hlocalhost -uroot -ppassword -e "CREATE USER 'demouser'@'%' IDENTIFIED WITH auth_pam AS 'oidc';"
# Check if the auth_pam plugin is enabled in Percona
docker compose exec percona mysql -hlocalhost -uroot -ppassword -e "SHOW PLUGINS;" | grep auth_pam
# auth_pam ACTIVE AUTHENTICATION auth_pam.so GPL
# Login as demouser
docker compose exec percona mysql -hlocalhost -udemouser -p'password_or_token_in_dot_env' -e "SELECT 1;"
# +---+
# | 1 |
# +---+
# | 1 |
# +---+
docker compose downSuccessful login will return a table with a single row containing the value 1.
This indicates that the pam_oidc module is working with MySQL.
Below are the old instructions for building and testing the pam_oidc module.
Click to expand
cd ./pam-oidc && cargo build; cd .. # DEBUG
cd ./pam-oidc && cargo build --release; cd .. # PRODCreate .env file in the root directory with the following:
DJ_AUTH_USER=
DJ_AUTH_PASSWORD=
DJ_AUTH_TOKEN=
See tests in tests subdirectory. The header comment gives hints how to run them.
Following Percona blog post:
❯ alias dkc='docker compose'
❯ dkc up --build -d percona
❯ dkc exec -it percona mysql -hlocalhost -uroot -ppassword -e "SHOW PLUGINS;" | grep auth_pam
auth_pam ACTIVE AUTHENTICATION auth_pam.so GPL
❯ dkc exec -it percona mysql -hlocalhost -uroot -ppassword
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 8.0.34-26 Percona Server (GPL), Release 26, Revision 0fe62c85
Copyright (c) 2009-2023 Percona LLC and/or its affiliates
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> CREATE USER ap_user IDENTIFIED WITH auth_pam;
Query OK, 0 rows affected (0.04 sec)
mysql> DELETE FROM mysql.user WHERE USER='';
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.02 sec)
mysql>
Bye
❯ dkc exec -it percona mysql -hlocalhost -uap_user -ppassword
# SuccessTo do in local folder
cargo init
cargo run
cargo build
cargo build --release
*as root
apk add g++ libressl-dev apt-get install libssl-dev pkg-config -y apt-get install musl-tools -y
apt-get install libssl-dev pkg-config build-essential libpam0g-dev libpam0g -y
*as user
cd /workspace/pam-oidc
cargo build
echo shh | PAM_TYPE=auth PAM_USER=raphael ./pam_oidc/target/release/pam_oidc ./sample.yaml
rustup target add x86_64-unknown-linux-gnu rustup target add x86_64-unknown-linux-musl rustup show cargo build --target x86_64-unknown-linux-musl --features vendored cargo build --release --target x86_64-unknown-linux-musl
cp pam-oidc/test /etc/pam.d/ cp pam-oidc/target/debug/libpam_oidc.so /lib/x86_64-linux-gnu/security/ python3 /workspace/test.py