summaryrefslogtreecommitdiffstats
path: root/doc/sphinx/arm/ext-radius.rst
blob: 028bfb2e8eae104a4df2f5326fc4d93d79c2a808 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
.. _radius:

RADIUS
======

.. _radius-overview:

RADIUS Overview
---------------

This hook library allows Kea to interact with two types of RADIUS
services: access and accounting. Although the most common DHCP and RADIUS
integration is done on the DHCP relay-agent level (DHCP clients send
DHCP packets to DHCP relays; those relays contact the RADIUS server and
depending on the response either send the packet to the DHCP server or
drop it), it does require DHCP relay hardware to support RADIUS
communication. Also, even if the relay has the necessary support, it is
often not flexible enough to send and receive additional RADIUS
attributes. As such, the alternative looks more appealing: to extend the
DHCP server to talk to RADIUS directly. That is the goal of this library.

.. note::

   This library can only be loaded by the :iscman:`kea-dhcp4` or the
   :iscman:`kea-dhcp6` process.

The major feature of this hook library is the ability to use RADIUS
authorization. When a DHCP packet is received, the Kea server sends an
Access-Request to the RADIUS server and waits for a response. The server
then sends back either an Access-Accept with specific client attributes,
or an Access-Reject. There are two cases supported here: first, the
Access-Accept includes a Framed-IP-Address attribute (for DHCPv4) or a
Framed-IPv6-Address attribute (for DHCPv6), which are interpreted by Kea as
instructions to assign the specified IPv4 or IPv6 address. This
effectively means RADIUS can act as an address-reservation database.

The second supported case is the ability to assign clients to specific
pools based on a RADIUS response. In this case, the RADIUS server sends
back an Access-Accept with a Framed-Pool attribute.
For both DHCPv4 and DHCPv6, Kea interprets this attribute as a client class.
With the addition of the ability to limit access to pools to
specific classes (see :ref:`classification-pools`), RADIUS can be
used to force the client to be assigned a dynamic address from a
specific pool. Furthermore, the same mechanism can be used to control
what kind of options the client gets if there are DHCP options
specified for a particular class.

.. _radius-config:

RADIUS Hook Library Configuration
---------------------------------

The RADIUS hook is a library that must be loaded by either :iscman:`kea-dhcp4` or
:iscman:`kea-dhcp6` servers. Unlike some other available hook libraries, this one
takes many parameters. For example, this configuration can be used:

.. parsed-literal::

    {
      "Dhcp4": {

        // Your regular DHCPv4 configuration parameters goes here.

        "hooks-libraries": [
          {
            // Note that RADIUS requires host-cache for proper operation,
            // so that library is loaded as well.
            "library": "/usr/local/lib/kea/hooks/libdhcp_host_cache.so"
          },
          {
            "library": "/usr/local/lib/kea/hooks/libdhcp_radius.so",
            "parameters": {

              // Specify where the dictionary is located.
              "dictionary": "/etc/kea/radius/dictionary",

              // Specify which address to use to communicate with RADIUS servers
              "bindaddr": "*"

              // More RADIUS parameters go here.
            }
          }
        ]
      }
    }

RADIUS is a complicated environment. As such, it is not feasible
to provide a default configuration that works for everyone.
However, we do have an example that showcases some of the more common
features. Please see ``doc/examples/kea4/hooks-radius.json`` in the Kea
sources.

The RADIUS hook library supports the following global configuration
flags:

-  ``bindaddr`` (default ``"*"``) - specifies the address to be used by the
   hook library in communication with RADIUS servers. The ``"*"`` special
   value tells the kernel to choose the address at hook library load time.

-  ``canonical-mac-address`` (default ``false``) - specifies whether MAC
   addresses in attributes follow the canonical RADIUS format (lowercase
   pairs of hexadecimal digits separated by ``-``).

-  ``client-id-pop0`` (default ``false``) - is used with
   :ischooklib:`libdhcp_flex_id.so`. Removes the leading zero (or pair of zeroes
   in DHCPv6) type in the client id (duid in DHCPv6). See
   ``client-id-printable`` for any value implications when used in conjunction
   with it.

-  ``client-id-printable`` (default ``false``) - checks whether the
   ``client-id``/``duid`` content is printable and uses it as is instead of in
   hexadecimal. Implies ``client-id-pop0`` and ``extract-duid`` as 0 and 255 are
   not printable.

-  ``deadtime`` (default ``0``) - is a mechanism that helps in sorting the
   servers such that the servers that have proved responsive so far are inquired
   first, and the servers that have proved unresponsive are left at the end. The
   deadtime value specifies the number of seconds after which a server is
   considered unresponsive. 0 disables the mechanism.

-  ``dictionary`` (default ``"/etc/kea/radius/dictionary"``) - is the
   attribute and value dictionary. Note that it is a critical parameter.
   A dictionary is provided by Kea and is set by default.

-  ``extract-duid`` (default ``true``) - extracts the embedded duid from an
   RFC-4361-compliant DHCPv4 client id. See ``client-id-printable`` for any
   value implications when used in conjunction with it.

-  ``identifier-type4`` (default ``"client-id"``) - specifies the identifier
   type to build the User-Name attribute. It should be the same as the
   host identifier. When :ischooklib:`libdhcp_flex_id.so` is used, then
   ``replace-client-id`` must be set to ``true`` and ``client-id`` must be used
   with ``client-id-pop0`` enabled.

-  ``identifier-type6`` (default ``"duid"``) - specifies the identifier type to
   build the User-Name attribute. It should be the same as the host
   identifier. When :ischooklib:`libdhcp_flex_id.so` is used, then
   ``replace-client-id`` must be set to ``true`` and ``duid`` must be used with
   ``client-id-pop0`` enabled.

-  ``nas-ports`` (default ``[]``), specifies the NAS port to use in place of
   a subnet ID (default behavior). It is an array of maps, each map having two
   elements at most: the mandatory NAS port value, and, optionally, a selector
   consisting of either a subnet id, a subnet prefix, or a shared-network name.
   If the selector is applied to the packet, the NAS port is used instead of the
   subnet id. When the subnet id is 0 or missing, the specified NAS port acts as
   a default. Its substition happens for all packets that did not match a
   selector.

-  ``realm`` (default ``""``) - is the default realm.

-  ``reselect-subnet-address`` (default ``false``) - enables subnet reselection
   according to the value of the Framed-IP-Address or, respectively,
   the Framed-IPv6-Address attribute from the RADIUS access response. With this
   flag enabled, if the IP address is not in range of the currently selected
   subnet, but is in range of another subnet that is selectable with regards to
   other criteria, the latter subnet is selected and used further in the lease
   assignment process.

-  ``reselect-subnet-pool`` (default ``false``) - enables subnet reselection
   according to the value of the Framed-Pool attribute from the RADIUS access
   response. With this flag enabled, if the currently selected subnet is not
   guarded by the client class represented by the attribute value, but there is
   another selectable subnet that is guarded by it, the latter subnet is
   selected and used further in the lease assignment process.
   This reselection is attempted first, and if successful, it prevents the
   function of reselect-subnet-address from coming into effect.

-  ``retries`` (default ``3``) - is the number of retries before trying the
   next server.

-  ``session-history`` (default ``""``) - is the name of the file providing
   persistent storage for accounting session history.

-  ``timeout`` (default ``10``) - is the number of seconds during which a
   response is awaited.

Two services are supported:

-  ``access`` - the authorization service.

-  ``accounting`` - the accounting service.

At the service level, three sections can be configured:

-  Servers that define RADIUS services that the library is expected to
   contact. Each server may have the following items specified:

   -  ``name`` - specifies the IP address of the server. A domain name may be
      used and will be resolved at hook library load time.

   -  ``port`` - specifies the UDP port of the server. By default, it is 1812
      for access and 1813 for accounting.

   -  ``secret`` - authenticates messages.

   When no server is specified, the service is disabled.

-  Attributes which define additional information that the Kea server
   sends to a RADIUS server. The parameter must be identified either
   by a name or type. Its value can be specified in one of three
   possible ways: ``data`` (which defines a plain text value), ``raw`` (which
   defines the value in hex), or ``expr`` (which defines an expression
   that is evaluated for each incoming packet independently).

   -  ``name`` - the name of the attribute.

   -  ``type`` - the type of the attribute. Either the type or the name must be
      provided, and the attribute must be defined in the dictionary.

   -  ``data`` - the first of three ways to specify the attribute content.
      It specifies the textual representation of the attribute content.

   -  ``raw`` - the second of three ways to specify the attribute content.
      It specifies the content in hexadecimal.

   -  ``expr`` - the last of the three ways to specify the attribute content.
      It specifies an evaluation expression on the DHCP query packet.
      Currently this is restricted to the access service.

    Attributes are supported only for the access service.

- The ``peer-updates`` boolean flag controls whether lease updates coming from
  an active High-Availability (HA) partner should result in an accounting
  request. This may be desirable to remove duplicates if HA partners are
  configured to send request to the same RADIUS server. The flag is enabled by
  default and only supported by the accounting service. The lease
  synchronization process at the startup of an HA node does not trigger a RADIUS
  accounting request, regardless of the value of this flag.

For example, to specify a single access server available on localhost
that uses ``"xyz123"`` as a secret, and tell Kea to send three additional
attributes (``User-Password``, ``Connect-Info``, and ``Configuration-Token``),
the following snippet could be used:

.. parsed-literal::

    {
      "parameters": {

        // Other RADIUS parameters here

        "access": {

          // This starts the list of access servers.
          "servers": [
            {
              // These are parameters for the first (and only) access server
              "name": "127.0.0.1",
              "port": 1812,
              "secret": "xyz123"
            }
          // Additional access servers could be specified here.
          ],

          // This defines a list of additional attributes Kea will send to each
          // access server in Access-Request.
          "attributes": [
            {
              // This attribute is identified by name (must be present in the
              // dictionary) and has static value (i.e. the same value will be
              // sent to every server for every packet).
              "name": "User-Password",
              "data": "mysecretpassword"
            },
            {
              // It is also possible to specify an attribute using its type,
              // rather than a name. 77 is Connect-Info. The value is specified
              // using hex. Again, this is a static value. It will be sent the
              // same for every packet and to every server.
              "type": 77,
              "raw": "65666a6a71"
            },
            {
               // This example shows how an expression can be used to send dynamic value.
               // The expression (see :ref:`classification-using-expressions`) may take any
               // value from the incoming packet or even its metadata e.g. the
               // interface it was received over from.
               "name": "Configuration-Token",
               "expr": "hexstring(pkt4.mac,':')"
            }
          ] // End of attributes
        }, // End of access

        // Accounting parameters.
        "accounting": {
          // This starts the list of accounting servers.
          "servers": [
            {
              // These are parameters for the first (and only) accounting server
              "name": "127.0.0.1",
              "port": 1813,
              "secret": "sekret"
            }
            // Additional accounting servers could be specified here.
          ]
        }
      }
    }

Customization is sometimes required for certain attributes by devices belonging
to various vendors. This is a great way to leverage the expression evaluation
mechanism. For example, MAC addresses which might be used as a convenience
value for the ``User-Password`` attribute are most likely to appear in colon-hexadecimal
notation (``de:ad:be:ef:ca:fe``), but they might need to be expressed in
hyphen-hexadecimal notation (``de-ad-be-ef-ca-fe``). Here's how to specify that:

.. code-block:: json

   {
      "parameters": {
         "access": {
            "attributes": [
               {
                  "name": "User-Password",
                  "expr": "hexstring(pkt4.mac, '-')"
               }
            ]
         }
      }
   }

And here's how to specify period-separated hexadecimal notation (``dead.beef.cafe``), preferred by Cisco devices:

.. code-block:: json

   {
      "parameters": {
         "access": {
            "attributes": [
               {
                  "name": "User-Password",
                  "expr": "concat(concat(concat(substring(hexstring(pkt4.mac, ''), 0, 4), '.'), concat(substring(hexstring(pkt4.mac, ''), 4, 4), '.'), concat(substring(hexstring(pkt4.mac, ''), 8, 4), '.'))"
               }
            ]
         }
      }
   }


For :ischooklib:`libdhcp_radius.so` to operate properly in DHCPv4,
:ischooklib:`libdhcp_host_cache.so` must also be loaded. The reason for this
is somewhat complex. In a typical deployment, the DHCP clients send
their packets via DHCP relay, which inserts certain Relay Agent
Information options, such as ``circuit-id`` or ``remote-id``. The values of
those options are then used by the Kea DHCP server to formulate the
necessary attributes in the Access-Request message sent to the RADIUS
server. However, once the DHCP client gets its address, it then renews
by sending packets directly to the DHCP server. As a result, the relays
are not able to insert their RAI options, and the DHCP server cannot send
the Access-Request queries to the RADIUS server by using just the
information from incoming packets. Kea needs to keep the information
received during the initial Discover/Offer exchanges and use it again
later when sending accounting messages.

This mechanism is implemented based on user context in host
reservations. (See :ref:`user-context` and :ref:`user-context-hooks` for
details.) The host-cache mechanism allows the information retrieved by
RADIUS to be stored and later used for sending access and accounting
queries to the RADIUS server. In other words, the host-cache mechanism
is mandatory, unless administrators do not want RADIUS communication for messages
other than Discover and the first Request from each client.

.. note::

   Currently the RADIUS hook library is incompatible with the
   ``early-global-reservations-lookup`` global parameter i.e.
   setting the parameter to ``true`` raises an error when the
   hook library is loaded.

.. note::

   Currently the RADIUS hook library is incompatible with the
   multi-subnet shared networks that have host reservations other
   than global. Loading the RADIUS hook library in a Kea DHCP server
   that has this configuration raises an error.

.. _radius-server-example:

RADIUS Server Setup Example
---------------------------

The RADIUS hook library requires at least one RADIUS server to function. One
popular open-source implementation is FreeRADIUS. This is how it can be
set up to enable basic functionality in Kea.

1. Install FreeRADIUS through the package manager or from the tarballs available
   on [the freeradius.org download page](https://freeradius.org/releases/).

2. Establish the FreeRADIUS configuration directory. It's commonly
   ``/etc/freeradius``, but it may be ``/etc/raddb``.

3. Generate certificates. Go to ``/etc/freeradius/certs``.
   Run ``./bootstrap`` or ``make``.
   Wait until finished. It should take a few seconds.

4. Check that the server is able to start.
   Running with the ``-X`` flag is a good way to display potential errors.
   Run ``radiusd -X`` or ``freeradius -X``, whichever is available.
   It should display ``Ready to process requests`` on the final line.

5. If the Kea DHCP server and the RADIUS server are on different machines,
   edit ``/etc/freeradius/clients.conf`` with the proper address under
   ``ipadddr``. This file is also where the secret is set, which needs to match
   the one set in the hook library's configuration.

6. If RADIUS is used for the purpose of authorizing DHCP clients, each DHCP
   client needs to have an entry in the authorize file, which can be commonly
   found at:

   - ``/etc/raddb/mods-config/files/authorize``
   - ``/etc/freeradius/3.0/mods-config/files/authorize``
   - ``/etc/freeradius/users`` (for RADIUS 2.x series)

   Entries need to have the password set which needs to match the password
   configured in the configuration of the RADIUS hook library under the
   ``User-Password`` attribute. Each entry can have zero, one or multiple
   attributes.

   In the following example, there are 6 entries with the password set to the
   client ID, which would need to be dynamically set in the hook library's
   configuration. Here's how the entries can look like:

   ::

       01:00:0c:01:02:03:04    Cleartext-password := "00:0c:01:02:03:04"

       01:00:0c:01:02:03:05    Cleartext-password := "00:0c:01:02:03:05"
           Framed-IP-Address = "192.0.2.5"

       01:00:0c:01:02:03:06    Cleartext-password := "00:0c:01:02:03:06"
           Framed-IP-Address = "192.0.2.6",
           Framed-Pool = "classical"

       00:03:00:01:00:0c:01:02:03:07    Cleartext-password := "00:0c:01:02:03:07"

       00:03:00:01:00:0c:01:02:03:08    Cleartext-password := "00:0c:01:02:03:08"
           Framed-IPv6-Address = "2001:db8::8"

       00:03:00:01:00:0c:01:02:03:09    Cleartext-password := "00:0c:01:02:03:09"
           Framed-IPv6-Address = "2001:db8::9",
           Framed-Pool = "classroom"

7. Accounting should work out of the box with Kea, but customizations are
   possible in the accounting file, which can be commonly found at:

   - ``/etc/radius-config/mods-config/files/accounting``
   - ``/etc/freeradius/3.0/mods-config/files/accounting``

.. _radius-lease-allocation:

RADIUS Workflows for Lease Allocation
-------------------------------------

The following diagrams show a high level view of how RADIUS assists with the
lease allocation process in :iscman:`kea-dhcp4` and :iscman:`kea-dhcp6`.

.. figure:: ../uml/radius.*

Somewhat tangential to lease allocation, and not shown in the diagrams above,
is the ``command_processed`` callout, which sends Accounting-Request messages
when a lease command is received.

.. _radius-differences:

Differences Between RADIUS Hook Libraries Prior To 2.4.0 and As Of 2.6.0
------------------------------------------------------------------------

The RADIUS hook library in 2.4.0 and prior versions relied on the FreeRADIUS
client library to function. Starting with 2.6.0 and onwards, the RADIUS hook
library is standalone with its own RADIUS client implementation and its own
RADIUS dictionary. There are differences:

.. list-table::
    :header-rows: 1

    * - Feature

      - Old

      - New

    * - Support for Attribute Data Types

      - string, ipaddr, ipv4prefix, integer, integer64, date, ifid, ipv6addr, ipv6prefix, tlv, abinary, byte, ether, short, signed, octets

      - string (can simulate any other unsupported data type too), ipaddr, integer, date (interpreted as integer), ipv6addr, ipv6prefix

    * - Names of Standard Attributes

      - Taken from the FreeRADIUS dictionary.

      - Taken from the Kea RADIUS dictionary and the IANA registry. There is an aliasing mechanism built into the library that ensures backward compatibility e.g. ``Password`` translates to the standard name of the attribute ``User-Password``.

    * - Resolution of RADIUS Server Domain Names

      - At run time.

      - At hook library load time.

    * - Automatic Deduction of Source Address for Reaching RADIUS Servers (configured with ``bindaddr: "*"``)

      - At run time.

      - At hook library load time.

    * - RADIUS Server Limit per Service

      - 8

      - Unlimited

    * - Support for Including Dictionaries Inside Dictionaries

      - Yes

      - No

    * - Support for Vendor Attributes

      - Yes

      - No

    * - Attribute Names and Attribute Values

      - Case-insensitive

      - Case-sensitive

    * - Integer Values

      - Do not require an attribute definition.

      - Must have an associated attribute definition in the dictionary.

    * - Reply-Message Presence in the Kea Logs

      - Only as part of the aggregated list of attributes in ``RADIUS_AUTHENTICATION_ACCEPTED``, ``RADIUS_ACCESS_CACHE_INSERT``, ``RADIUS_ACCESS_CACHE_GET`` log messages.

      - Also has a dedicated ``RADIUS_REPLY_MESSAGE_ATTRIBUTE`` message per each Reply-Message attribute logged after a valid RADIUS reply is received.

    * - Behavior of Multiple Attributes of the Same Type (except Reply-Message)

      - Experimentally, only the **first** attribute on the wire from an Access-Accept message is considered.

      - Experimentally, only the **last** attribute on the wire from an Access-Accept message is considered.