10 The protocol design looks a lot like kerberos. The authorizer "KDC"
11 role is served by the monitor, who has a database of shared secrets
12 for each entity. Clients and non-monitor daemons all start by
13 authenticating with the monitor to obtain tickets, mostly referreed to
14 in the code as authorizers. These tickets provide both
15 *authentication* and *authorization* in that they include a
16 description of the *capabilities* for the entity, a concise structured
17 description of what actions are allowed, that can be interpreted and
18 enforced by the service daemons.
23 - A write-up from 2012 on cephx as it existed at that time by Peter
24 Reiher: :ref:`cephx_2012_peter`
29 - *monitor(s)*: central authorization authority
30 - *service*: the set of all daemons of a particular type (e.g., all
32 - *client*: an entity or principal that is accessing the service
33 - *entity name*: the string identifier for a principal
34 (e.g. client.admin, osd.123)
35 - *ticket*: a bit of data that cryptographically asserts identify and
38 - *principal*: a client or daemon, identified by a unique entity_name,
39 that shares a secret with the monitor.
40 - *principal_secret*: principal secret, a shared secret (16 bytes)
41 known by the principal and the monitor
42 - *mon_secret*: monitor secret, a shared secret known by all monitors
43 - *service_secret*: a rotating secret known by all members of a
44 service class (e.g., all OSDs)
46 - *auth ticket*: a ticket proving identity to the monitors
47 - *service ticket*: a ticket proving identify and authorization to a
54 ``{foo, bar}^secret`` denotes encryption by secret.
60 The authentication messages described here are specific to the cephx
61 auth implementation. The messages are transferred by the Messenger
62 protocol or by MAuth messages, depending on the version of the
63 messenger protocol. See also :ref:`msgr2-protocol`.
65 An initial (messenger) handshake negotiates an authentication method
66 to be used (cephx vs none or krb or whatever) and an assertion of what
67 entity the client or daemon is attempting to authenticate as.
69 Phase I: obtaining auth ticket
70 ------------------------------
72 The cephx exchange begins with the monitor knowing who the client
73 claims to be, and an initial cephx message from the monitor to the
77 CephxServerChallenge {
78 u64 server_challenge # random (by server)
81 The client responds by adding its own challenge, and calculating a
82 value derived from both challenges and its shared key
87 u16 CEPHX_GET_AUTH_SESSION_KEY
90 u8 2 # 2 means nautilus+
91 u64 client_challenge # random (by client)
92 u64 key = {client_challenge ^ server_challenge}^principal_secret # (roughly)
93 blob old_ticket # old ticket, if we are reconnecting or renewing
94 u32 other_keys # bit mask of service keys we want
100 u8 1 # 2 means nautilus+
101 u64 client_challenge # random (by client)
102 u64 key = {client_challenge + server_challenge}^principal_secret # (roughly)
103 blob old_ticket # old ticket, if we are reconnecting or renewing
106 The monitor looks up principal_secret in database, and verifies the
107 key is correct. If old_ticket is present, verify it is valid, and we
108 can reuse the same global_id. (Otherwise, a new global_id is assigned
113 u16 CEPHX_GET_AUTH_SESSION_KEY
116 u8 encoding_version = 1
117 u32 num_tickets ( = 1)
118 ticket_info # (N = 1)
120 plus (for Nautilus and later)::
122 u32 connection_secret_len # in bytes
123 connection_secret^session_key
124 u32 other_keys_len # bytes of other keys (encoded)
126 u8 encoding_version = 1
128 service_ticket_info * N # for each service ticket
134 u32 service_id # CEPH_ENTITY_TYPE_AUTH
136 {CephXServiceTicket service_ticket}^principal_secret
137 {CephxTicketBlob ticket_blob}^existing session_key # if we are renewing a ticket,
138 CephxTicketBlob ticket_blob # otherwise
141 service_ticket_info {
142 u32 service_id # CEPH_ENTITY_TYPE_{OSD,MDS,MGR}
144 {CephXServiceTicket service_ticket}^principal_secret
145 CephxTicketBlob ticket_blob
149 CryptoKey session_key # freshly generated (even if old_ticket is present)
150 utime_t expiration # now + auth_mon_ticket_ttl
154 u64 secret_id # which service ticket encrypted this; -1 == monsecret, otherwise service's rotating key id
155 {CephXServiceTicketInfo ticket}^mon_secret
158 CephxServiceTicketInfo {
159 CryptoKey session_key # same session_key as above
164 EntityName name # client's identity, as proven by its possession of principal_secret
165 u64 global_id # newly assigned, or from old_ticket
166 utime_t created, renew_after, expires
167 AuthCapsInfo # what client is allowed to do
168 u32 flags = 0 # unused
171 So: for each ticket, principal gets a part that it decrypts with its
172 secret to get the session_key (CephxServiceTicket). And the
173 CephxTicketBlob is opaque (secured by the mon secret) but can be used
174 later to prove who we are and what we can do (see CephxAuthorizer
177 For Nautilus+, we also include the service tickets.
179 The client can infer that the monitor is authentic because it can
180 decrypt the service_ticket with its secret (i.e., the server has its
184 Phase II: Obtaining service tickets (pre-nautilus)
185 --------------------------------------------------
187 Now the client needs the keys used to talk to non-monitors (osd, mds,
192 u16 CEPHX_GET_PRINCIPAL_SESSION_KEY
194 CephxAuthorizer authorizer
195 CephxServiceTicketRequest {
196 u32 keys # bitmask of CEPH_ENTITY_TYPE_NAME (MGR, OSD, MDS, etc)
202 u8 AUTH_MODE_AUTHORIZER (1)
204 u32 service_id # CEPH_ENTITY_TYPE_*
205 CephxTicketBlob auth_ticket
206 {CephxAuthorize msg}^session_key
211 u64 nonce # random from client
212 bool have_challenge = false # not used here
213 u64 server_challenge_plus_one = 0 # not used here
216 The monitor validates the authorizer by decrypting the auth_ticket
217 with ``mon_secret`` and confirming that it says this principal is who
218 they say they are in the CephxAuthorizer fields. Note that the nonce
219 random bytes aren't used here (the field exists for Phase III below).
221 Assuming all is well, the authorizer can generate service tickets
222 based on the CEPH_ENTITY_TYPE_* bits in the ``keys`` bitmask.
224 The response looks like::
226 CephxResponseHeader {
227 u16 CEPHX_GET_PRINCIPAL_SESSION_KEY
230 u8 encoding_version = 1
237 u32 service_id # CEPH_ENTITY_TYPE_{OSD,MGR,MDS}
239 {CephXServiceTicket service_ticket}^principal_secret
240 CephxTicketBlob ticket_blob
244 CryptoKey session_key
249 u64 secret_id # which version of the (rotating) service ticket encrypted this
250 {CephXServiceTicketInfo ticket}^rotating_service_secret
253 CephxServiceTicketInfo {
254 CryptoKey session_key
261 utime_t created, renew_after, expires
262 AuthCapsInfo # what you are allowed to do
263 u32 flags = 0 # unused
266 This concludes the authentication exchange with the monitor. The
267 client or daemon now has tickets to talk to the mon and all other
271 Phase III: Opening a connection to a service
272 --------------------------------------------
274 When a connection is opened, an "authorizer" payload is sent::
278 u8 AUTH_MODE_AUTHORIZER (1)
280 u32 service_id # CEPH_ENTITY_TYPE_*
281 CephxTicketBlob auth_ticket
282 {CephxAuthorize msg}^session_key
287 u64 nonce # random from client
288 bool have_challenge = false
289 u64 server_challenge_plus_one = 0
292 Note that prior to the Luminous v12.2.6 or Mimic v13.2.2 releases, the
293 CephxAuthorize msg did not contain a challenge, and consisted only
298 u64 nonce # random from client
301 The server will inspect the auth_ticket CephxTicketBlob (by decrypting
302 it with its current rotating service key). If it is a pre-v12.2.6 or
303 pre-v13.2.2 client, the server immediately replies with::
306 {CephxAuthorizeReply reply}^session_key
310 CephxAuthorizeReply {
314 Otherwise, the server will respond with a challenge (to prevent replay
318 {CephxAuthorizeChallenge challenge}^session_key
322 CephxAuthorizeChallenge {
323 u64 server_challenge # random from server
326 The client decrypts and updates its CephxAuthorize msg accordingly,
327 resending most of the same information as before::
331 u8 AUTH_MODE_AUTHORIZER (1)
333 u32 service_id # CEPH_ENTITY_TYPE_*
334 CephxTicketBlob auth_ticket
335 {CephxAuthorize msg}^session_key
342 u64 nonce # (new) random from client
343 bool have_challenge = true
344 u64 server_challenge_plus_one # server_challenge + 1
347 The server validates the ticket as before, and then also verifies the
348 msg nonce has it's challenge + 1, confirming this is a live
349 authentication attempt (not a replay).
351 Finally, the server responds with a reply that proves its authenticity
352 to the client. It also includes some entropy to use for encryption of
353 the session, if it is needed for the mode.::
356 {CephxAuthorizeReply reply}^session_key
360 CephxAuthorizeReply {
362 u32 connection_secret_length
366 Prior to nautilus, there is no connection secret::
368 CephxAuthorizeReply {
372 The client decrypts and confirms that the server incremented nonce
373 properly and that this is thus a live authentication request and not a
377 Rotating service secrets
378 ------------------------
380 Daemons make use of a rotating secret for their tickets instead of a
381 fixed secret in order to limit the severity of a compromised daemon.
382 If a daemon's secret key is compromised by an attacker, that daemon
383 and its key can be removed from the monitor's database, but the
384 attacker may also have obtained a copy of the service secret shared by
385 all daemons. To mitigate this, service keys rotate periodically so
386 that after a period of time (auth_service_ticket_ttl) the key the
387 attacker obtained will no longer be valid.::
391 u16 CEPHX_GET_ROTATING_KEY
396 u16 CEPHX_GET_ROTATING_KEY
399 {CryptoKey service_key}^principal_secret
401 That is, the new rotating key is simply protected by the daemon's
404 Note that, as an implementation detail, the services keep the current
405 key and the prior key on hand so that the can continue to validate
406 requests while the key is being rotated.