Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
be1f72d
Refactor: libcrmcommon: Make client PSK initialization more obvious.
clumens Feb 6, 2026
7217917
Refactor: libcrmcommon: pcmk__tls_client_add_psk_key should take a us…
clumens Feb 6, 2026
b0b835e
Refactor: daemons: Make execd PSK initialization more obvious.
clumens Feb 6, 2026
2a5fddb
Feature: daemons: Add support for PSK authentication for remote CIB ops.
clumens Mar 25, 2026
f3811a2
Refactor: libcrmcommon: Add a raw param to pcmk__tls_client_add_psk_key.
clumens Mar 26, 2026
fca51a0
Refactor: libcrmcommon: Add a raw param to pcmk__load_key.
clumens Mar 26, 2026
d4d6c99
Feature: libcib: Add support for PSK authentication for remote CIB ops.
clumens Mar 25, 2026
d6052b7
Doc: sysconfig: Remove a redundant sentence from PCMK_authkey_location.
clumens Mar 25, 2026
6e07e5f
Doc: Pacemaker Explained: Remove a redundant sentence from PCMK_authk…
clumens Mar 25, 2026
5966121
Doc: Pacemaker Administration: Document remote CIB admin with PSK.
clumens Mar 25, 2026
64294a7
Test: cts-scheduler: Remove remote-clear-port from test XML files.
clumens Feb 6, 2026
0037f76
API: libcrmcommon: Deprecate remote-clear-port.
clumens Feb 6, 2026
425f780
Feature: libcrmcommon: Deprecate anonymous authentication.
clumens Feb 6, 2026
c310837
Refactor: libcib: Use pcmk__xe_set_props in cib_tls_signon.
clumens Feb 9, 2026
a140e49
Refactor: libcib: Clean up includes in cib_remote.c
clumens Mar 4, 2026
d2384ca
Refactor: libcrmcommon: The tls_rc argument can no longer be NULL.
clumens Apr 17, 2026
4c62f77
Refactor: libcrmcommon: Always set gnutls_rc on gnutls errors...
clumens Apr 17, 2026
50b4956
Refactor: libcib: Return more definite errors from cib_tls_signon.
clumens Apr 10, 2026
33f5665
Refactor: libcib: Split TLS setup out into its own function.
clumens Apr 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cts/scheduler/xml/history-1.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="34" num_updates="163" validate-with="pacemaker-3.7" remote-tls-port="9898" remote-clear-port="9999" cib-last-written="Fri Jul 13 13:51:05 2012" have-quorum="1" dc-uuid="pcmk-1">
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="34" num_updates="163" validate-with="pacemaker-3.7" remote-tls-port="9898" cib-last-written="Fri Jul 13 13:51:05 2012" have-quorum="1" dc-uuid="pcmk-1">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
Expand Down
2 changes: 1 addition & 1 deletion cts/scheduler/xml/migrate-fencing.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="46" num_updates="177" validate-with="pacemaker-3.7" remote-tls-port="9898" remote-clear-port="9999" cib-last-written="Fri Jul 13 13:51:09 2012" have-quorum="1" dc-uuid="pcmk-4">
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="46" num_updates="177" validate-with="pacemaker-3.7" remote-tls-port="9898" cib-last-written="Fri Jul 13 13:51:09 2012" have-quorum="1" dc-uuid="pcmk-4">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
Expand Down
2 changes: 1 addition & 1 deletion cts/scheduler/xml/migrate-shutdown.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cib crm_feature_set="3.0.6" admin_epoch="1" epoch="47" num_updates="322" validate-with="pacemaker-3.7" remote-tls-port="9898" remote-clear-port="9999" cib-last-written="Fri Jul 13 13:51:09 2012" have-quorum="1" dc-uuid="101">
<cib crm_feature_set="3.0.6" admin_epoch="1" epoch="47" num_updates="322" validate-with="pacemaker-3.7" remote-tls-port="9898" cib-last-written="Fri Jul 13 13:51:09 2012" have-quorum="1" dc-uuid="101">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
Expand Down
2 changes: 1 addition & 1 deletion cts/scheduler/xml/probe-3.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cib crm_feature_set="3.0.1" admin_epoch="1" epoch="49" num_updates="34" validate-with="pacemaker-3.7" remote-tls-port="9898" remote-clear-port="9999" cib-last-written="Fri Jul 13 13:51:12 2012" have-quorum="1" dc-uuid="pcmk-2">
<cib crm_feature_set="3.0.1" admin_epoch="1" epoch="49" num_updates="34" validate-with="pacemaker-3.7" remote-tls-port="9898" cib-last-written="Fri Jul 13 13:51:12 2012" have-quorum="1" dc-uuid="pcmk-2">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
Expand Down
2 changes: 1 addition & 1 deletion cts/scheduler/xml/probe-4.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cib crm_feature_set="3.0.1" admin_epoch="1" epoch="49" num_updates="34" validate-with="pacemaker-3.7" remote-tls-port="9898" remote-clear-port="9999" cib-last-written="Fri Jul 13 13:51:12 2012" have-quorum="1" dc-uuid="pcmk-2">
<cib crm_feature_set="3.0.1" admin_epoch="1" epoch="49" num_updates="34" validate-with="pacemaker-3.7" remote-tls-port="9898" cib-last-written="Fri Jul 13 13:51:12 2012" have-quorum="1" dc-uuid="pcmk-2">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
Expand Down
2 changes: 1 addition & 1 deletion cts/scheduler/xml/promoted-demote-2.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="125" num_updates="1946" validate-with="pacemaker-3.7" remote-tls-port="9898" remote-clear-port="9999" cib-last-written="Fri Jul 13 13:51:07 2012" have-quorum="1" dc-uuid="pcmk-1">
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="125" num_updates="1946" validate-with="pacemaker-3.7" remote-tls-port="9898" cib-last-written="Fri Jul 13 13:51:07 2012" have-quorum="1" dc-uuid="pcmk-1">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
Expand Down
2 changes: 1 addition & 1 deletion cts/scheduler/xml/promoted-unmanaged-monitor.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="37" num_updates="90" validate-with="pacemaker-3.7" remote-tls-port="9898" remote-clear-port="9999" cib-last-written="Fri Jul 13 13:51:08 2012" have-quorum="1" dc-uuid="pcmk-3">
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="37" num_updates="90" validate-with="pacemaker-3.7" remote-tls-port="9898" cib-last-written="Fri Jul 13 13:51:08 2012" have-quorum="1" dc-uuid="pcmk-3">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
Expand Down
2 changes: 1 addition & 1 deletion cts/scheduler/xml/unmanaged-promoted.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="53" num_updates="19" validate-with="pacemaker-3.7" remote-tls-port="9898" remote-clear-port="9999" cib-last-written="Fri Jul 13 13:51:22 2012" have-quorum="1" dc-uuid="pcmk-1">
<cib crm_feature_set="3.0.5" admin_epoch="1" epoch="53" num_updates="19" validate-with="pacemaker-3.7" remote-tls-port="9898" cib-last-written="Fri Jul 13 13:51:22 2012" have-quorum="1" dc-uuid="pcmk-1">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
Expand Down
64 changes: 52 additions & 12 deletions daemons/based/based_remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#define HAVE_PAM 1
#endif

#define CREDFILE PACEMAKER_CONFIG_DIR "/cib-credentials"

static pcmk__tls_t *tls = NULL;

int remote_fd = 0;
Expand Down Expand Up @@ -692,29 +694,67 @@ based_remote_init(void)
{
const char *port_s = NULL;
int port = 0;
int rc = pcmk_rc_ok;
bool have_psk = false;

port_s = pcmk__xe_get(the_cib, PCMK_XA_REMOTE_TLS_PORT);

if ((pcmk__scan_port(port_s, &port) == pcmk_rc_ok) && (port > 0)) {
// @TODO Implement pre-shared key authentication (see T961)
int rc = pcmk__init_tls(&tls, true, false);
if ((pcmk__scan_port(port_s, &port) != pcmk_rc_ok) || (port <= 0)) {
goto try_clear_port;
}

if (rc != pcmk_rc_ok) {
pcmk__err("Failed to initialize TLS: %s. Not starting TLS listener ",
"on port %d", pcmk_rc_str(rc), port);
remote_tls_fd = -1;
/* X509 certificates take precedence over PSK in pcmk__init_tls,
* so don't perform any of the following (potentially noisy) checks
* if we don't care about their results.
*/
if (!pcmk__x509_enabled()) {
bool file_exists = false;

} else {
pcmk__notice("Starting TLS listener on port %d", port);
remote_tls_fd = init_remote_listener(port);
have_psk = pcmk__cred_file_useable(CREDFILE, &file_exists);

if (!have_psk && file_exists) {
/* The credential file exists but doesn't have the right owner
* or permissions. Don't fall back to anonymous on config
* errors.
*/
pcmk__err("Not starting TLS listener on port %d", port);
goto try_clear_port;
}

pcmk__warn("Falling back to anonymous authentication for remote "
"CIB connections");
}

/* Now that we know whether to fall back to anonymous authentication
* or not, we can actually initialize TLS support.
*/
rc = pcmk__init_tls(&tls, true, have_psk);
if (rc != pcmk_rc_ok) {
pcmk__err("Failed to initialize TLS: %s. Not starting TLS listener ",
"on port %d", pcmk_rc_str(rc), port);

remote_tls_fd = -1;
goto try_clear_port;
}

if (tls->cred_type == GNUTLS_CRD_PSK) {
gnutls_psk_set_server_credentials_file(tls->credentials.psk_s,
CREDFILE);
}

pcmk__notice("Starting TLS listener on port %d", port);
remote_tls_fd = init_remote_listener(port);

try_clear_port:
/* Regardless of whether or not we successfully enabled remote-tls-port,
* we also want to try to enable remote-clear-port as well.
*/
port_s = pcmk__xe_get(the_cib, PCMK_XA_REMOTE_CLEAR_PORT);

if ((pcmk__scan_port(port_s, &port) == pcmk_rc_ok) && (port > 0)) {
pcmk__warn("Starting clear-text listener on port %d. This is insecure; "
PCMK_XA_REMOTE_TLS_PORT " is recommended instead.", port);
pcmk__warn("Starting clear-text listener on port %d. This is insecure "
"and will be removed in a future release. Use "
PCMK_XA_REMOTE_TLS_PORT " instead.", port);
remote_fd = init_remote_listener(port);
}
}
39 changes: 32 additions & 7 deletions daemons/execd/remoted_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,23 @@ tls_server_dropped(gpointer user_data)

// \return 0 on success, -1 on error (gnutls_psk_server_credentials_function)
static int
lrmd_tls_server_key_cb(gnutls_session_t session, const char *username, gnutls_datum_t * key)
lrmd_tls_server_key_cb(gnutls_session_t session, const char *username,
gnutls_datum_t *key)
{
/* First, check that the client's username is valid. For Pacemaker
* Remote node connections, all clients will have the same username so
* we don't need to look it up anywhere.
*/
if (!pcmk__str_eq(DEFAULT_REMOTE_USERNAME, username, pcmk__str_none)) {
pcmk__err("Expected remote username " DEFAULT_REMOTE_USERNAME ", but "
"got %s", username);
return -1;
}

/* All Pacemaker Remote connections use the same key, too, so we don't
* need to do any lookups here either. Just attempt to load the key from
* disk (or cache) and put it in the key variable.
*/
return (lrmd__init_remote_key(key) == pcmk_rc_ok)? 0 : -1;
}

Expand Down Expand Up @@ -379,12 +394,22 @@ lrmd_init_remote_tls_server(void)
if (!pcmk__x509_enabled()) {
gnutls_datum_t psk_key = { NULL, 0 };

pcmk__tls_add_psk_callback(tls, lrmd_tls_server_key_cb);

/* The key callback won't get called until the first client connection
* attempt. Do it once here, so we can warn the user at start-up if we can't
* read the key. We don't error out, though, because it's fine if the key is
* going to be added later.
/* Register the callback function that will be used to load the key
* when a client connects.
*/
gnutls_psk_set_server_credentials_function(tls->credentials.psk_s,
lrmd_tls_server_key_cb);

/* gnutls doesn't need us to load the remote key up front. It will use
* the callback we just registered to load the key for each client when
* it attempts to connect. We do so here (1) to warn the user at start-up
* if we can't read the key, and (2) to cache the key so it's faster to
* authenticate each client.
*
* This also has the side effect of allowing the administrator to start
* the cluster without the Pacemaker Remote node key, then add it later,
* and have clients succeed in connecting. I don't know why this would
* be useful.
*/
if (lrmd__init_remote_key(&psk_key) != pcmk_rc_ok) {
pcmk__warn("A cluster connection will not be possible until the "
Expand Down
82 changes: 72 additions & 10 deletions doc/sphinx/Pacemaker_Administration/configuring.rst
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,22 @@ It is possible to run configuration commands from a machine that is not part of
the cluster.

For security reasons, this capability is disabled by default. If you wish to
allow remote access, set the ``remote-tls-port`` (encrypted) or
``remote-clear-port`` (unencrypted) CIB properties (attributes of the ``cib``
element). Encrypted communication can be performed keyless (which makes it
subject to man-in-the-middle attacks), but a better option is to also use
TLS certificates.
allow remote access, set the ``remote-tls-port`` CIB property (attribute of
the ``cib`` element). Communication can be performed with TLS certificates,
or using pre-shared keys (PSK). If both TLS certificates and PSK are configured,
Comment thread
clumens marked this conversation as resolved.
only TLS certificates will be enabled.


.. note::

Pacemaker must have been built with PAM support for remote access to work.
You can check by running ``pacemakerd --features``. If the output contains
**pam**, remote access is supported. *(since 3.0.0; before 3.0.0, in a build
without PAM support, all remote connections are accepted without any
authentication)*

Configuring TLS Certificates
____________________________

To enable TLS certificates, it is recommended to first set up your own
Certificate Authority (CA) and generate a root CA certificate. Then create a
Expand Down Expand Up @@ -249,13 +260,64 @@ the daemon user's password:
Optionally, :ref:`CIB_crl_file <CIB_crl_file>` may be set to the location of a
Certificate Revocation List in PEM format.

Configuring Pre-Shared Keys (PSK)
_________________________________

To enable pre-shared keys, the first thing you need is a key file on any cluster
nodes that require access. The key file must be named ``cib-credentials`` and
be placed in the |PCMK_CONFIG_DIR| directory. It must be readable only by the
Pacemaker daemon user. Each line in this file is a username:key pair. The
``psktool`` program shipped with gnutls can be used to manage this file.

For instance, to create a new key for |CRM_DAEMON_USER|, do the following:

.. code-block:: none

# psktool -u hacluster -p /etc/pacemaker/cib-credentials
Generating a random key for user 'hacluster'
Key stored to cib-credentials
# cat /etc/pacemaker/cib-credentials
hacluster:c496618a37acb82672d968de46fb6865eca340409ae5b2620e7d2320c6059a7f
# chown hacluster:haclient /etc/pacemaker/cib-credentials
# chmod 600 /etc/pacemaker/cib-credentials

On the client side, set the following environment variables to connect to
the cluster:

* :ref:`CIB_port <CIB_port>` (required)
* :ref:`CIB_server <CIB_server>`
* :ref:`CIB_user <CIB_user>`
* :ref:`CIB_passwd <CIB_passwd>`
* :ref:`CIB_encrypted <CIB_encrypted>`
* :ref:`CIB_key_file <CIB_key_file>` (required)

``CIB_key_file`` should point to a local file whose contents are the key that
was previously generated on the server. It should only be readable by the local
user. For instance, from the above example, it would look like:

.. code-block:: none

# cat ~/cib-credentials
c496618a37acb82672d968de46fb6865eca340409ae5b2620e7d2320c6059a7f

As an example, if **node1** is a cluster node, and the CIB is configured with
``remote-tls-port`` set to 1234, the administrator could read the current
cluster configuration using the following commands, and would be prompted for
the daemon user's password:

.. code-block:: none

# export CIB_server=node1; export CIB_port=1234; export CIB_encrypted=true
# export CIB_key_file=~/cib-credentials
# cibadmin -Q

.. note::

Pacemaker must have been built with PAM support for remote access to work.
You can check by running ``pacemakerd --features``. If the output contains
**pam**, remote access is supported. *(since 3.0.0; before 3.0.0, in a build
without PAM support, all remote connections are accepted without any
authentication)*
As of Pacemaker 3.0.2, even with the use of PSK authentication, a username
and password is additionally required to login to the CIB itself. Due to a
limitation in how Pacemaker authentication works, ``CIB_user`` must be set
to |CRM_DAEMON_USER| and the credentials file must have an entry for
|CRM_DAEMON_USER|.

.. rubric:: Footnotes

Expand Down
2 changes: 1 addition & 1 deletion doc/sphinx/Pacemaker_Explained/cluster-options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ holds. So the decision was made to place them in an easy-to-find location.
- If set to a TCP port number, the CIB manager will listen for remote
connections on this port, to allow for CIB administration from hosts not
in the cluster. No encryption is used, so this should be used only on a
protected network.
protected network. *(deprecated since 3.0.2)*
* - .. _cib_last_written:

.. index::
Expand Down
2 changes: 0 additions & 2 deletions doc/sphinx/Pacemaker_Explained/local-options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,6 @@ whose location varies by OS (most commonly ``/etc/sysconfig/pacemaker`` or
or the |CRM_DAEMON_GROUP| group), and its contents must be identical on
all nodes.

This is an alternative to using X509 certificates.

* - .. _pcmk_remote_pid1:

.. index::
Expand Down
2 changes: 0 additions & 2 deletions etc/sysconfig/pacemaker.in
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,6 @@
# permissions to either the @CRM_DAEMON_USER@ user or the @CRM_DAEMON_GROUP@
# group), and its contents must be identical on all nodes.
#
# This is an alternative to using X509 certificates.
#
# Default: PCMK_authkey_location="@PACEMAKER_CONFIG_DIR@/authkey"

# PCMK_remote_pid1 (Advanced Use Only)
Expand Down
Loading