Skip to content

Add support for PSK to remote CIB and deprecate insecure methods#4051

Open
clumens wants to merge 15 commits intoClusterLabs:mainfrom
clumens:remote-cib-psk
Open

Add support for PSK to remote CIB and deprecate insecure methods#4051
clumens wants to merge 15 commits intoClusterLabs:mainfrom
clumens:remote-cib-psk

Conversation

@clumens
Copy link
Copy Markdown
Contributor

@clumens clumens commented Feb 9, 2026

No description provided.

@clumens clumens requested a review from nrwahl2 February 9, 2026 15:50
@clumens
Copy link
Copy Markdown
Contributor Author

clumens commented Feb 9, 2026

CI failure is unrelated to this PR:

[2026-02-09T16:06:35.420Z] logging.c:111:14: error: case value not in enumerated type 'GLogLevelFlags' [-Werror,-Wswitch]
[2026-02-09T16:06:35.420Z]   111 |         case G_LOG_LEVEL_MASK:
[2026-02-09T16:06:35.420Z]       |              ^
[2026-02-09T16:06:35.420Z] 1 error generated.

Let's see if #4052 fixes it.

@clumens
Copy link
Copy Markdown
Contributor Author

clumens commented Feb 10, 2026

Rebased on main to pick up that logging fix so we can get the green check.

@clumens clumens force-pushed the remote-cib-psk branch 2 times, most recently from 37ff190 to 947f634 Compare March 17, 2026 18:30
@nrwahl2 nrwahl2 added the review: in progress PRs that are currently being reviewed label Mar 23, 2026
* connections, all clients will have the same username so we don't need
* to look it up anywhere.
*/
if (!pcmk__str_eq(CRM_DAEMON_USER, username, pcmk__str_none)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CIB manager doesn't require this (see cib_remote_auth()). This caused me a bit of confusion. But I guess, counterintuitively, this is unrelated to the username and password used for authentication to the CIB manager. The TLS credentials are set using CRM_DAEMON_USER in this same commit.

I'm trying to think of any reason why that might be a problem when the client requests to use a different user (via the CIB_user environment variable). I don't have any specific complaint at the moment.

I don't think it matters -- CRM_DAEMON_USER is used at the GnuTLS level, and CIB_user is used at the CIB manager level, without the two interacting.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, our authentication is confusing and in the interests of trying to keep things as similar within pacemaker as possible, I might have also made things more confusing.

You're right, there are two layers of authentication, and everything I've been doing here should be at the gnutls layer. What I've set up here does mean that the only valid username is CRM_DAEMON_USER, but that is in line with how the Pacemaker Remote node authentication works - the only valid username there is DEFAULT_REMOTE_USERNAME.

Ideally we'd use the username/key system that gnutls wants us to use, but having different systems for different portions of pacemaker seemed more confusing than just using the same goofy system everywhere.

Checking the username is kind of pointless, but it just seems odd to me to have authentication code that doesn't check it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have also made things more confusing.

My initial answer was along the lines of "Heheh, I don't think so. That'd be tough to do. Besides, if we had different keys for different usernames, we'd have to check those on the server side."

Thinking a little bit more, I'm on the fence. We could use the gnutls credential file scheme and avoid needing a callback function. That way we could support different keys for different CIB_users.

I'm trying to think of whether this would make a difference for anyone. I'm starting to think that it could.

  • On the one hand, maybe a cluster has multiple admin users. It could make sense to give each of them their own credential file (with a PSK) on the remote admin machine, so that they can only log in as themselves -- especially if they have different ACLs or something.
  • On the other hand, each of them already has to enter the CIB_user's password to complete the signon.
  • Back to the first hand:
    • The different credential files could act like a sort of 2FA, so that the remote admin user needs both the correct PSK in the credentials file and the correct password. (But: we give precedence to X509 for whatever reason, and I'm not sure off the top of my head whether our X509 scheme has an analogue where each user has their own cert.)
    • Couldn't this eliminate the need for entering the CIB_user password altogether? I'm wondering if we could allow passwordless authentication when PSK and/or X509 is configured for a particular user. It doesn't seem like it would be grossly insecure -- as an analogy, I'm thinking of copying SSH keys, which is common practice.

You've made an argument for consistency with remote node authentication. That's a reasonable argument, as consistency tends to make things much easier to, um, reason about. However, IIRC there is no real place for another username in remote node authentication. All of that stuff is done within Pacemaker -- almost as an implementation detail but with the administrator needing to provide a credentials file when setting up the cluster. The remote CIB administration stuff has a logical place for different user accounts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* On the one hand, maybe a cluster has multiple admin users. It could make sense to give each of them their own credential file (with a PSK) on the remote admin machine, so that they can only log in as themselves -- especially if they have different ACLs or something.

Yes, this does make sense.

  * The different credential files could act like a sort of 2FA, so that the remote admin user needs both the correct PSK in the credentials file and the correct password. (But: we give precedence to X509 for whatever reason, and I'm not sure off the top of my head whether our X509 scheme has an analogue where each user has their own cert.)

I have to re-learn how all the certificate stuff works every time I need to look at it just because it's so complicated and different from anything else I ever look at. So with that in mind... at the moment, each client can have its own X509 cert. A "client" would typically be a system that an admin would connect from, so not technically exactly the same as a per-user cert, but pretty close and maybe close enough that the distinction doesn't matter.

They still have to login with a username and password. I'm not sure whether removing that layer is a good idea or not.

  * Couldn't this eliminate the need for entering the `CIB_user` password altogether? I'm wondering if we could allow passwordless authentication when PSK and/or X509 is configured for a particular user. It doesn't seem like it would be grossly insecure -- as an analogy, I'm thinking of copying SSH keys, which is common practice.

Yes, definitely. That was something I thought of earlier too. And if we could justify getting rid of the user/password combination with certs (which again, not sure that's safe) then I think we could eliminate all of the PAM related code.

You've made an argument for consistency with remote node authentication. That's a reasonable argument, as consistency tends to make things much easier to, um, reason about. However, IIRC there is no real place for another username in remote node authentication. All of that stuff is done within Pacemaker -- almost as an implementation detail but with the administrator needing to provide a credentials file when setting up the cluster. The remote CIB administration stuff has a logical place for different user accounts.

I agree, and another thing to think about when it comes to the remote node authentication is that the client/server model there is flipped. The remote node is the server, and the cluster is the client. Having multiple usernames there makes less sense.

I think it's worth looking into this and trying to get it done in the next couple days. I would definitely like to be more aligned with how gnutls wants us to work, and I like the idea of being able to deprecate CIB_user/CIB_passwd.

@nrwahl2 nrwahl2 removed the review: in progress PRs that are currently being reviewed label Mar 24, 2026
Copy link
Copy Markdown
Contributor

@nrwahl2 nrwahl2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some substantial thoughts in #4051 (comment). If we want to reconsider the approach, we can do that either now or later. Feel free to merge this and get the basic feature in place, if you would like.

clumens added 15 commits March 26, 2026 13:37
To me, pcmk__tls_add_psk_key is not especially obviously named.  This
function should only be called on TLS clients - it's not some general
purpose PSK key management function.  It has no purpose on the server
side of a connection.  Therefore, rename it and update the doxygen to be
clearer.

Ref T961
…ername.

Pre-shared keys in gnutls are tied to a specific username.  See the man
page for gnutls_psk_set_client_credentials or
https://www.gnutls.org/manual/html_node/PSK-credentials.html for more
details.

Right now, we only support PSK for remote node authentication, and we
only support a single username for that.  We'll be adding PSK support to
remote CIB authentication in a later patch, and that will allow
specifying other usernames.

Ref T961
gnutls expects that for PSK authentication, there will be a password
file somewhere with the format "username:key".  The server tells gnutls
where that password file is, and then when a client connects, it gives
the server a username and key.  gnutls reads that file and looks for a
match.

execd doesn't do that.  For Pacemaker Remote node connections, every
client always has the same username (DEFAULT_REMOTE_USERNAME, or "lrmd")
and there's only one key.  That's because the key is just a single file
that's referenced in /etc/sysconfig/pacemaker.  In order for us to make
gnutls work the way we want, we have to register a callback function.

This is probably okay because in the remote node world, the cluster is
the client and the remote node is the server.  It makes some sense that
each remote node would have the same username.

This callback function will get called every time a client attempts to
connect.  It will load the key from disk (which, because we only support
a single key, it's probably been cached - I think this is why we even
have the caching layer for keys in the first place) into a variable, and
then gnutls will check its validity.

We additionally try to load the key from disk outside of gnutls's
control as a way to log an error if it's not present, and I suppose as a
way to have it cached for the first connection.

Note one behavioral change: previously, our callback function wasn't
even checking the username.  This is somewhat pointless since the
username will always be the same, but it still seems worth doing as a
best practice.

Because all of the above only applies to execd (PSK support for remote
CIB operations will not work this way), just get rid of
pcmk__tls_add_psk_callback and inline its contents in execd.

Ref T961
This is the server side of things.  The way this works is that the
server has a file where each line is "username:key".  If this file is
present and useable, PSK authentication will be supported.  If it's just
present but not useable, we assume the admin made a mistake in
configuration and error out.  Otherwise, we'll fall back to anonymous
authentication for now.  gnutls will handle reading this file, looking
for a user match, and checking the key.

This patch is made more complicated by refusing to use a credentials
file with the wrong ownerships or permissions.  It's annoying, but
that's the way a lot of security software works and I think it's
probably a best practice.

Note that the location of the credentials file is not configurable.

Ref T961
This function can be used to add two kinds of PSK keys:

(1) Binary (or raw, as gnutls calls them) keys.  This is just a binary
blob of data and is what Pacemaker Remote keys tend to be.  Various
documents online describe using dd to create the authentication key for
remote nodes, and I think pcs does something similar.

(2) Text files with name:key rows.  Here, the key is a string of hex
characters.  This is what remote CIB administration will use.

gnutls needs to be told what format the key is in when it's being
loaded.  I feel like this is opening us up to some pretty annoying bugs,
but I don't see a way around it if we're to support both kinds of things
we want to do.  In particular, I'm worried that someone will be using a
text-based Pacemaker Remote key.

Ref T961
This is for the exact same reasons as pcmk__tls_client_add_psk_key.  Hex
keys won't work with gnutls unless the trailing newline is stripped from
the read string.

Ref T961
This is the client side of things.  For the client, we need to get the
username and key from somewhere.  I've chosen to use $CIB_user and to
overload $CIB_key_file (which is already in use for X509 cert support)
for this purpose.  Overloading the latter should be fine - there's
nowhere we check just that environment variable to decide on cert
support, and you can't use both certs and PSK at the same time.

Given those two environment variables, all we have to do is load the key
and pass it to gnutls which takes care of the rest.  Again, this patch
is made more complicated by refusing to use a credentials file with the
wrong ownerships or permissions

Ref T961
This CIB property is deprecated in favor of remote-tls-port which is
more secure and has been supported since at least 2014.  For now, it
will still be recognized but will log a warning.  Also mark it as
deprecated in the docs and remove references to it being something that
you can use.

Ref T961
This is an insecure authentication method where we use an encrypted TLS
channel for communication, but there's no authentication on the channel
beyond that.  Well, that's not completely true - for remote CIB
operations, you do still need a username and password.  However, the
username is always the same so that's easy for people to figure out.

Instead, people should be using X509 certificates or PSK.  A future
release will remove support for anonymous authentication and require use
of one of those other mechanisms.

Fixes T961
@clumens
Copy link
Copy Markdown
Contributor Author

clumens commented Mar 27, 2026

@nrwahl2 The patches here that are identical to the first version are:

  • Refactor: libcrmcommon: Make client PSK initialization more obvious.
  • Refactor: libcrmcommon: pcmk__tls_client_add_psk_key should take a username. (commit message is slightly different)
  • Test: cts-scheduler: Remove remote-clear-port from test XML files.
  • Refactor: libcib: Use pcmk__xe_set_props in cib_tls_signon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants