✨ Commits existing images to git
- Implemented sync-roles.sh to synchronize Active Directory group memberships as MariaDB roles and user accounts. - Created Containerfile for building a custom ldap2pg image with patched YAML decoding. - Added provision-user-db.sh for provisioning user databases and roles based on LDAP synchronization. - Introduced a new Containerfile for MariaDB with PAM authentication via pam_ldap. - Configured PAM service for MariaDB logins and added necessary plugins for LDAP authentication. - Implemented health checks and entrypoint scripts for MariaDB and pgpool containers. - Enhanced PostgreSQL image with additional extensions and custom pg_hba.conf for improved security and functionality.
This commit is contained in:
20 files changed
+1023
No files matched your search
@@ -0,0 +1,56 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
ARG MARIADB_VERSION=latest
|
||||
|
||||
FROM mariadb:${MARIADB_VERSION}
|
||||
|
||||
# ── AD/LDAP authentication via PAM ──────────────────────────────────────────
|
||||
# MariaDB Community has no native LDAP auth plugin, so AD logins go through the
|
||||
# auth_pam plugin -> a PAM "mariadb" service -> daemonless pam_ldap doing an
|
||||
# LDAP search+bind against Active Directory. This is the analogue of the pgpool
|
||||
# `ldap` method in pool_hba.conf; deliberately NO SSSD/nslcd daemon is added.
|
||||
#
|
||||
# libpam-ldap is the daemonless PAM/LDAP module. The auth_pam plugin ships with
|
||||
# recent MariaDB; the separate plugin package (older layouts) is installed
|
||||
# best-effort and also fixes the setuid auth_pam_tool helper permissions.
|
||||
# Either source must leave auth_pam.so in place: 10-plugins.cnf loads it
|
||||
# unconditionally, so a missing .so would only surface as a server that refuses
|
||||
# to start.
|
||||
RUN set -eu; \
|
||||
apt-get update; \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
libpam-ldap \
|
||||
ca-certificates \
|
||||
gettext-base; \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
mariadb-plugin-auth-pam || true; \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
plugin=/usr/lib/mysql/plugin/auth_pam.so; \
|
||||
[ -e "$plugin" ] || { echo "auth_pam: missing $plugin" >&2; exit 1; }
|
||||
|
||||
# ── Layered configuration ───────────────────────────────────────────────────
|
||||
# Mirror the postgres image: image-owned defaults load first, user overrides
|
||||
# last (last-wins). The stock image already reads /etc/mysql/conf.d and
|
||||
# /etc/mysql/mariadb.conf.d; we append two include dirs AFTER those so:
|
||||
# image.conf.d -> our defaults (override the base image's 50-server.cnf)
|
||||
# site.conf.d -> a clean "mount your *.cnf here" area (wins over everything)
|
||||
RUN set -eu; \
|
||||
mkdir -p /etc/mysql/image.conf.d /etc/mysql/site.conf.d; \
|
||||
{ \
|
||||
echo '!includedir /etc/mysql/image.conf.d/'; \
|
||||
echo '!includedir /etc/mysql/site.conf.d/'; \
|
||||
} >> /etc/mysql/mariadb.cnf
|
||||
COPY conf.d/ /etc/mysql/image.conf.d/
|
||||
|
||||
# PAM service definition for MariaDB logins (auth_pam calls service "mariadb").
|
||||
COPY pam.d/mariadb /etc/pam.d/mariadb
|
||||
|
||||
# Entrypoint wrapper: renders /etc/pam_ldap.conf from env (keeps the AD bind
|
||||
# secret out of the image), then hands off to the stock mariadb entrypoint.
|
||||
COPY --chmod=0755 docker-entrypoint.sh /usr/local/bin/ldap-entrypoint.sh
|
||||
|
||||
# Report health via the image's bundled healthcheck helper.
|
||||
HEALTHCHECK --interval=10s --timeout=5s --retries=5 --start-period=15s \
|
||||
CMD healthcheck.sh --connect --innodb_initialized || exit 1
|
||||
|
||||
ENTRYPOINT ["ldap-entrypoint.sh"]
|
||||
CMD ["mariadbd"]
|
||||
@@ -0,0 +1,11 @@
|
||||
# Image-owned plugin preload (analogue of the postgres image's
|
||||
# shared_preload_libraries in 10-extensions.conf). auth_pam provides Active
|
||||
# Directory logins via PAM -> pam_ldap.
|
||||
[mariadb]
|
||||
plugin_load_add = auth_pam
|
||||
|
||||
# Make auth_pam use the mysql_clear_password protocol instead of the interactive
|
||||
# "dialog" one. Required for MaxScale: its clear_pw_passthrough only speaks
|
||||
# mysql_native_password / mysql_clear_password to backends, never dialog. The
|
||||
# password is sent in cleartext, so TLS must be on (99-tls.cnf) — it is.
|
||||
pam_use_cleartext_plugin = 1
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Render pam_ldap's config from the environment so the AD bind credentials are
|
||||
# never baked into the image. pam_ldap performs a search+bind against AD: bind
|
||||
# as the service account, find the user by ${LDAP_LOGIN_ATTR}, then re-bind as
|
||||
# that DN with the supplied password to verify it — the same shape as pgpool's
|
||||
# `ldap` method (see pool_hba.conf).
|
||||
: "${LDAPURI:?LDAPURI is required (e.g. ldaps://hecate.ad.kritikos.io)}"
|
||||
: "${LDAP_BASE:?LDAP_BASE is required (e.g. DC=ad,DC=kritikos,DC=io)}"
|
||||
: "${LDAPBINDDN:?LDAPBINDDN is required (AD service/bind account)}"
|
||||
: "${LDAPPASSWORD:?LDAPPASSWORD is required}"
|
||||
: "${LDAP_LOGIN_ATTR:?LDAP_LOGIN_ATTR is required (e.g. sAMAccountName)}"
|
||||
# demand = validate the AD cert against the trust store; relax to 'allow' only
|
||||
# for testing, or add your internal CA to the image and keep 'demand'.
|
||||
: "${LDAP_TLS_REQCERT:?LDAP_TLS_REQCERT is required (demand|allow|never)}"
|
||||
|
||||
umask 077
|
||||
# pam_ldap.so on this image reads /etc/ldap.conf (the PADL default path), and
|
||||
# libpam-ldap ships a placeholder there (base dc=example,dc=net) that otherwise
|
||||
# shadows our config and makes every login fail. Render both paths.
|
||||
for conf in /etc/ldap.conf /etc/pam_ldap.conf; do
|
||||
cat > "$conf" <<EOF
|
||||
uri ${LDAPURI}
|
||||
base ${LDAP_BASE}
|
||||
binddn ${LDAPBINDDN}
|
||||
bindpw ${LDAPPASSWORD}
|
||||
scope sub
|
||||
referrals no
|
||||
pam_login_attribute ${LDAP_LOGIN_ATTR}
|
||||
pam_filter objectclass=User
|
||||
tls_cacertdir /etc/ssl/certs
|
||||
tls_reqcert ${LDAP_TLS_REQCERT}
|
||||
EOF
|
||||
chmod 600 "$conf"
|
||||
done
|
||||
|
||||
# Grant mysql read access to the host TLS key (mode 0640, owned by GID
|
||||
# ${CERTS_GID}). compose exposes that GID via `group_add`, but the stock
|
||||
# entrypoint drops root -> mysql with gosu, which rebuilds mysql's groups from
|
||||
# /etc/group and discards the compose-added GID — mysql then can't read ssl_key
|
||||
# and MariaDB aborts with "Unable to get private key". While still root, put
|
||||
# mysql in a group with that GID so it survives the privilege drop.
|
||||
: "${CERTS_GID:?CERTS_GID is required (GID owning the host TLS key)}"
|
||||
if [ "$(id -u)" = '0' ]; then
|
||||
if getent group "${CERTS_GID}" >/dev/null; then
|
||||
certgroup="$(getent group "${CERTS_GID}" | cut -d: -f1)"
|
||||
else
|
||||
groupadd -g "${CERTS_GID}" hostcerts
|
||||
certgroup=hostcerts
|
||||
fi
|
||||
usermod -aG "$certgroup" mysql
|
||||
else
|
||||
echo "ldap-entrypoint: not root (uid $(id -u)); left group membership unchanged (CERTS_GID=${CERTS_GID})" >&2
|
||||
fi
|
||||
|
||||
exec docker-entrypoint.sh "$@"
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Runs once on first cluster init (empty datadir), the analogue of
|
||||
# init_pgpool_user.sql. Creates the infrastructure accounts (MaxScale monitor +
|
||||
# service, and the replication user) on the backend. All use native password
|
||||
# auth (NOT pam) — they are service accounts, not human AD logins. Passwords
|
||||
# come from the environment so nothing secret is committed to a .sql file, and
|
||||
# the root password goes via MYSQL_PWD (read by the client) rather than -p so it
|
||||
# never appears in the process list.
|
||||
|
||||
: "${MARIADB_ROOT_PASSWORD:?}"
|
||||
: "${MAXSCALE_MONITOR_PASSWORD:?}"
|
||||
: "${MAXSCALE_SERVICE_PASSWORD:?}"
|
||||
: "${MARIADB_REPL_PASSWORD:?}"
|
||||
|
||||
MYSQL_PWD="${MARIADB_ROOT_PASSWORD}" mariadb --protocol=socket -uroot <<SQL
|
||||
-- Monitor account: mariadbmon health checks, replication state, and failover.
|
||||
CREATE USER IF NOT EXISTS 'maxscale_monitor'@'%' IDENTIFIED BY '${MAXSCALE_MONITOR_PASSWORD}';
|
||||
GRANT BINLOG MONITOR, SLAVE MONITOR, REPLICATION SLAVE, REPLICATION MASTER ADMIN,
|
||||
REPLICATION SLAVE ADMIN, READ_ONLY ADMIN, RELOAD, PROCESS,
|
||||
SHOW DATABASES, EVENT
|
||||
ON *.* TO 'maxscale_monitor'@'%';
|
||||
|
||||
-- Service account: reads the user tables so MaxScale can authenticate clients
|
||||
-- and route them (pass-through auth defers the real check to the backend PAM).
|
||||
CREATE USER IF NOT EXISTS 'maxscale_service'@'%' IDENTIFIED BY '${MAXSCALE_SERVICE_PASSWORD}';
|
||||
GRANT SELECT ON mysql.* TO 'maxscale_service'@'%';
|
||||
GRANT SHOW DATABASES ON *.* TO 'maxscale_service'@'%';
|
||||
|
||||
-- Replication account: the replica's IO thread uses this to stream the binlog.
|
||||
CREATE USER IF NOT EXISTS 'repl'@'%' IDENTIFIED BY '${MARIADB_REPL_PASSWORD}';
|
||||
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
|
||||
SQL
|
||||
@@ -0,0 +1,6 @@
|
||||
# PAM service for MariaDB auth_pam logins (accounts created IDENTIFIED VIA pam
|
||||
# USING 'mariadb'). Authenticate + authorize against Active Directory through
|
||||
# the daemonless pam_ldap module; its connection settings live in
|
||||
# /etc/pam_ldap.conf, rendered at container start from the environment.
|
||||
auth required pam_ldap.so
|
||||
account required pam_ldap.so
|
||||
Reference in new issue
Block a user