diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 14:11:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 14:11:00 +0000 |
commit | af754e596a8dbb05ed8580c342e7fe02e08b28e0 (patch) | |
tree | b2f334c2b55ede42081aa6710a72da784547d8ea /doc/antora/modules/howto/pages/protocols | |
parent | Initial commit. (diff) | |
download | freeradius-af754e596a8dbb05ed8580c342e7fe02e08b28e0.tar.xz freeradius-af754e596a8dbb05ed8580c342e7fe02e08b28e0.zip |
Adding upstream version 3.2.3+dfsg.upstream/3.2.3+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
17 files changed, 2312 insertions, 0 deletions
diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/enable.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/enable.adoc new file mode 100644 index 0000000..2824bd0 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/enable.adoc @@ -0,0 +1,213 @@ +== Enabling the DHCP service + +A major difference between configuring FreeRADIUS as a DHCP server versus most +other DHCP software such as ISC DHCP is that other software typically uses a +single monolithic configuration file whereas FreeRADIUS has a collection of +configuration files. This reflects the modularity of FreeRADIUS; attempting to +put the entire configuration in a single file would result in a very difficult +to read configuration. + +The root of the FreeRADIUS configuration may be in a different location on the +filesystem depending on how FreeRADIUS has been installed. This directory will +be referred to as `<raddb>` below. The sample configuration files are well +commented describing what each configuration option does. + +FreeRADIUS compiled from source will default to `/usr/local/etc/raddb`. +Pre-built packages will default to either `/etc/raddb` or +`/etc/freeradius`. + + +=== Enable the DHCP virtual server + +The FreeRADIUS configuration separates each network service that it provides +into "virtual servers". A number of sample virtual server definitions are +provided in `<raddb>/sites-available`, one of which is the sample +configuration for a DHCP service. + +Sites may be added to the working configuration by either creating a symlink to +them or copying them to `<conf>/sites-enabled` depending on how you wish to +manage future upgrades. + +[TIP] +==== +As with other package-managed configuration files, package upgrades will not +automatically replace files that you have edited but you will need to resolve +any local differences. Creating copies avoids the need to resolve conflicts +during a package upgrade. +==== + +Add the DHCP virtual server to the active configuration: + +[source,shell] +---- +cd <raddb>/sites-enabled +ln -s ../sites-available/dhcp . +---- + +or: + +[source,shell] +---- +cd <raddb>/sites-enabled +cp ../sites-available/dhcp . +---- + +The sample configuration has been set up in such a way that it is initially +safe. It will not actually take over live DHCP serving on the network when it +is simply enabled until it is configured to do so. Rather is set up for testing +prior to going live. + +The virtual server begins with a `listen` section. In this section your need to +modify the following configuration items: + +`ipaddr`:: The IP address to listen on. +`src_ipaddr`:: The source IP for unicast packets. +`port`:: The port to listen on. Setting this to `67` will make the DHCP service live on the network. +`interface`:: The network interface to listen on. +`broadcast`:: Allow broadcast packets. For most live systems this will need to be set to `yes`. + +Below the `listen` section, there are sections that define how to respond to +each of the DHCP packet types. Most installations will require that you review +the settings for `DHCP-Discover` and `DHCP-Request`. + +Their contents contain directives in the FreeRADIUS policy language, "unlang". +Many examples are provided which have been carefully described. + + +=== Enable SQL and IP pool modules + +FreeRADIUS has many modules to support different aspects of the functionality +required for the network protocols it can process. The two of most significance +for DHCP are `dhcp_sql` and `dhcp_sqlippool`. As with virtual servers, a +number of example module configurations are available in +`<raddb>/mods-available`. +These should be symlinked or copied into `<raddb>/mods-enabled` in order to +enable them. + + +==== Configure the `dhcp_sql` module + +Add the `dhcp_sql` module to the active configuration: + +[source,shell] +---- +cd <raddb>/mods-enabled +ln -s ../mods-available/dhcp_sql . +---- + +or: + +[source,shell] +---- +cd <raddb>/mods-enabled +cp ../mods-available/dhcp_sql . +---- + +The `dhcp_sql` module should be configured with the connection parameters for +whichever database is to be used. The key configuration items are: + +`dialect`:: Which SQL dialect is in use. +`driver`:: Which driver to use to access the database. For most databases this + is `rlm_sql_<dialect>`, however Microsoft SQL Server has a choice of + drivers. + +Then, there are configuration options that are unique to each database, +including connection details. For most databases these are: + +`server`:: The host name or IP address of the database server. +`port`:: The port to connect to the database server on. +`login`:: The user name used to connect to the database. +`password`:: The password for authenticating to the database. +`radius_db`:: The name of the database. + +[NOTE] +==== +SQLite does not use these connection options, rather the `filename` +option within the `sqlite` section is used to determine where the database +will be stored. +==== + + +==== Configure the `dhcp_sqlippool` module + +Add the `dhcp_sqlippool` module to the active configuration: + +[source,shell] +---- +cd <raddb>/mods-enabled +ln -s ../mods-available/dhcp_sqlippool . +---- + +or + +[source,shell] +---- +cd <raddb>/mods-enabled +cp ../mods-available/dhcp_sqlippool . +---- + +The `dhcp_sqlippool` module must be configured. The key configuration +items are: + +`dialect`:: Set this to the same SQL dialect as in the `sql` module. +`offer_duration`:: How long an IP is offered to the client in a DHCP OFFER. +`lease_duration`:: How long an IP is leased to the client in a DHCP ACK. + + +=== Provision the database + +You should provision your database by creating a user for FreeRADIUS (matching +the configuration that you have previously provided) and then loading the +schema. The procedure for doing this will vary according to the database +server. + +The schema, stored procedure definition and any additional setup scripts for +your database are in `<raddb>/mods-config/sql/ippool-dhcp/{dialect}/`. + +=== Test FreeRADIUS startup + +Once you have provisioned your schema, created a user account and granted +access to the user, you should be able to start FreeRADIUS. + +If FreeRADIUS has been configured correctly then the output of `ss` will +contain a line showing that FreeRADIUS is listening for DHCP packets on the +designated interface on port 67: + +.Example of FreeRADIUS listening on `<interface>` for DHCP packets +================================================================== + # ss -lunp + Netid Recv-Q Send-Q Local Address:Port ... + udp 0 0 0.0.0.0%<interface>:67 ... users:(("radiusd",...)) +================================================================== + +Note that if the database is inaccessible then FreeRADIUS will normally refuse +to start. + +The FreeRADIUS wiki contains extensive information about debugging FreeRADIUS +startup issues that we do not repeat in any detail here. + +Essentially, stop your init system from repeatedly trying to launch FreeRADIUS: + +[source,shell] +---- +service radiusd stop +---- + +Then start FreeRADIUS manually in debug mode: + +[source,shell] +---- +radiusd -X +---- + +Carefully read the output since this will tell you why FreeRADIUS was unable to +start. + +Once you have fixed the issue start FreeRADIUS as normal: + +[source,shell] +---- +service radiusd start +---- + +Now xref:protocols/dhcp/test.adoc[test the DHCP service] to ensure that it is responding to requests. diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/index.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/index.adoc new file mode 100644 index 0000000..fde2202 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/index.adoc @@ -0,0 +1,35 @@ += FreeRADIUS DHCP server + +This guide describes how FreeRADIUS can be used in place of ISC DHCP or ISC Kea +to provide a significantly more performant and, above all, more flexible DHCP +server. + +This guide provides a suggested configuration that should be somewhat familiar +to anyone who has previously implemented DHCP using the most frequently used +features of other DHCP server software. + +The modular design of FreeRADIUS means that there is no one "right" way to +implement the DHCP service. FreeRADIUS allows you to put together a "mix and +match" approach. + +For example you can manage the leases in an SQL database. You might then hard +code certain DHCP reply parameters within configuration and then look up +additional parameters using a datastore such as: + + * a local file such as a structured text file or an SQLite database + * an organisational LDAP directory + * an SQL or "no SQL" database + * a remote endpoint such as a RESTful HTTP API + +The policy language and modular configuration of FreeRADIUS is sufficiently +powerful and that almost any aspect of the server's behaviour can be customised +to implement even the most sophisticated DHCP configurations. + +== Sections in this guide + +This guide is organised into four parts that should be read in order: + +1. xref:protocols/dhcp/prepare.adoc[Preparation] +2. xref:protocols/dhcp/enable.adoc[Enabling the DHCP service] +3. xref:protocols/dhcp/test.adoc[Testing the DHCP service] +4. xref:protocols/dhcp/policy.adoc[Defining the DHCP policy] diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy.adoc new file mode 100644 index 0000000..d8f1bcb --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy.adoc @@ -0,0 +1,14 @@ +== Defining the DHCP policy + +Now that FreeRADIUS is successfully running as a DHCP server it is necessary to +configure a DHCP policy so that it returns correctly formed responses to the DHCP +requests that it receives. + +This involves a number of steps: + + * xref:protocols/dhcp/policy_ippool_creation.adoc[Defining the IP address pools.] + * xref:protocols/dhcp/policy_common_options.adoc[Defining the options that are common to all replies.] + * xref:protocols/dhcp/policy_network_options.adoc[Defining the options for the network from which the request originates and ensuring that IP addresses are allocated from the correct pool.] + * xref:protocols/dhcp/policy_subnet_options.adoc[Defining the options for the subnet to which this issued IP address belongs.] + * xref:protocols/dhcp/policy_device_options.adoc[Defining the device, class and group based options specific to the device.] + * xref:protocols/dhcp/policy_ippool_access.adoc[Using device properties to restrict access to certain pools.] diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc new file mode 100644 index 0000000..949868d --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_common_options.adoc @@ -0,0 +1,80 @@ +== Configure common reply options + +FreeRADIUS includes a powerful xref:unlang/index.adoc[policy language] called +"unlang". + +Statements in unlang may be used to call further policies, update attribute +lists and invoke modules. There are also control flow statements (if, +switch, etc.) typical of most imperative languages. + +FreeRADIUS has a number attribute lists that it maintains as it processes +packets within the virtual server sections. Most relevant to DHCP are +`request`, `control` and `reply`. + +The DHCP options from the current request packet are provided in the +`request` list. This includes fixed DHCP parameters such as +`DHCP-Client-Hardware-Address`, optional parameters such as +`DHCP-Requested-IP-Address`, and parameters synthesised by FreeRADIUS such as +`DHCP-Message-Type` and `DHCP-Network-Subnet`. + +DHCP options can be set by updating their value in the `reply` list. This +forms the basis of the packet returned to the client. + +In the default DHCP server configuration, a "policy" (akin to a subroutine) is +used to set common options for reply packets. The policy is found in +`<raddb>/policy.d/dhcp`. + +Look at the contents of the `dhcp_common` section and set any global options +applicable to all clients in this policy. + +[source,unlang] +---- +dhcp_common { + update reply { + &DHCP-Domain-Name-Server := 8.8.8.8 + &DHCP-Domain-Name-Server += 8.8.4.4 + &DHCP-Subnet-Mask := 255.255.255.0 + &DHCP-Router-Address := 192.0.2.1 + ... + } +} +---- + +Note, FreeRADIUS has four main operators for assigning values to attributes: + +`=`:: Add the attribute to the list, if and only if an attribute of the same + name is not already present in that list. +`:=`:: Add the attribute to the list. If any attribute of the same name is + already present in that list it is replaced with the new one. +`+=`:: Add the attribute to the tail of the list, even if attributes of the + same name are already present in the list. +`^=`:: Add the attribute to the head of the list, even if attributes of the + same name are already present in the list. + +These operators allow for attributes to be set to default values and then +overwritten, e.g. setting a default lease time, but then overwriting it for +a particular group of clients. + +Attributes in the `control` list are not returned in the DHCP reply packets +but instead govern aspects of server's behaviour. + +To use an SQL backend for either static or dynamic IP allocation, un-comment +the block: + +[source,unlang] +---- +update control { + &Pool-Name := "local" +} +dhcp_sqlippool +---- + +The `Pool-Name` control attribute is used in looking up addresses in the +database. The line containing `dhcp_sqlippool` is a call to invoke an +instance of a module with that name. This module is responsible for assigning a +free IP address into the `DHCP-Your-IP-Address` reply attribute from the pool +identified by `Pool-Name`. + +Here `Pool-Name` is being set to a constant value (`local`) indicating +that a single pool is to be used. If you have multiple pools, then replace this +`update` block with logic to map clients to the correct pool, as described below. diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_device_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_device_options.adoc new file mode 100644 index 0000000..05845ea --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_device_options.adoc @@ -0,0 +1,310 @@ +== Configure "device", "class" and "group" options + +Beyond the global, network and subnet options already described, most sites +will have a number of group or class based options, and have a requirement for +setting reply parameters against individual devices. + +In general, FreeRADIUS does not differentiate between "classes" (memberships +defined by some attribute of the DHCP request) and "groups" (memberships +defined by some manually aggregation related devices, typically based on lists +of MAC address). + +The sample DHCP configuration provided with FreeRADIUS makes use of an internal +attribute `DHCP-Group-Name` to support the setting of different options for +different groups of devices. + +In general the groups to which a device belongs is determined during the +processing of a request and these are added as instances of the +`DHCP-Group-Name` attribute. This may be by performing a test on one or more +request parameters (akin to a "class"), hash-based lookup of up all of part of +an attribute in a local list (akin to a "subclass"), or doing the same using a +remote datastore (SQL, LDAP, REST API, etc). + +FreeRADIUS can then iterate over `DHCP-Group-Name` to set group-specific +options. + +We describe some of these options in more detail. + +=== Directly in Policy + +Simple class options can be written directly into policy. This is most +suited to those options that rarely change and are based on attributes in the +request such as the `User-Class`. + +Consider the ISC DHCP configuration snippet: + +[source,iscdhcp] +---- +filename "undionly.kpxe"; +class "pxeclient" { + match option substring(user-class,0,4); +} +subclass "pxeclient" "iPXE" { + filename "http://my.web.server/boot_script.php"; +} +---- + +Or the equivalent Kea configuration: + +[source,isckea] +---- +"Dhcp4": { + "option-data": [ + { "name": "boot-file-name", "data": "undionly.kpxe" } + ], + "client-classes": [ + { + "name": "pxeclient", + "test": "substring(option[77],0,4) == 'iPXE'", + "option-data": [ + { + "name": "boot-file-name", + "data": "http://my.web.server/boot_script.php" + } + ] + } + ] + ... +} +---- + +These define the "filename" DHCP option differently based on whether or not the +supplied "user-class" option begins with "iPXE". + +FreeRADIUS provides multiple ways for this to be configured. + +For example, the following "unlang" policy implements the class options defined +above: + +[source,unlang] +---- +if (&DHCP-User-Class && "%{substring:&DHCP-User-Class 0 4}" == "iPXE") { + update reply { + &DHCP-Boot-Filename := "http://my.web.server/boot_script.php" + } +} else { + update reply { + &DHCP-Boot-Filename := "undionly.kpxe" + } +} +---- + +Policy-based configuration of DHCP options is also useful for complex matching. +For example, the following Unlang sets the DHCP-Boot-Filename parameter based +on the request's DHCP-Client-Identifier using regular expression captures, +provided that it matches the given format: + +[source,unlang] +---- +if (&DHCP-Client-Identifier && \ + "%{string:DHCP-Client-Identifier}" =~ /^RAS([0-9])-site([A-Z])$/) { + update reply { + &DHCP-Boot-Filename := "rasboot-%{1}-%{2}.kpxe" + } +} +---- + +=== In Text Files + +The `files` module that has already been described for global, network and +subnet options can also be used to apply options to groups of clients. + +Firstly we must defined a mapping from a set of clients clients to their +respective groups. One option for this is to use the `passwd` module, for +which a sample configuration is included. + +Firstly symlink or copy the module configuration +`<raddb>/mods-available/dhcp_passwd` into `<raddb>/mods-enabled/`. The +suggested configuration expects the group membership file to be in +`<raddb>/mods-config/files/dhcp_groups` and take the form of: + +[source,config] +---- +<group1 name>|<hardware address>,<hardware address>,<hardware address> +<group2 name>|<hardware address>,<hardware address> +---- + +i.e. one line for each group starting with the group name followed by a pipe +character and then a comma-separated list of hardware addresses. + +The `allow_multiple_keys` option allows for a host to be a member of +more than one group. + +Sample configuration for looking up group options is contained in +`<raddb>/policy.d/dhcp` in the `dhcp_group_options` policy and in +`<raddb>/mods-available/dhcp_files` as the `dhcp_set_group_options` instance. + +The same data file `<raddb>/mods-config/files/dhcp` is used to lookup +group options as was used for global and network options. In this instance, +add entries with the group name as the key such as: + +[source,config] +---- +group1 + DHCP-Log-Server := 10.10.0.100, + DHCP-LPR-Server := 10.10.0.200 + +group2 + DHCP-LPR-Server := 192.168.20.200 +---- + +=== In the SQL Database + +Policy and files are both read during startup and editing them while +FreeRADIUS is running will not result in any changes in behaviour. If +you require regular changes to DHCP options, then storing them in +an SQL database provides greater flexibility since the queries will be run in +response to each DHCP packet rather than requiring the server to be restarted. + +DHCP reply options for devices (including network-specific options) can be +fetched from SQL using an arbitrary lookup key. This can be performed multiple +times as necessary using different contexts, for example to first set +subnet-specific options and then to set group-specific options. + +The default schema contains three tables to support this: + +"dhcpreply" contains reply options for a given identifier (e.g. MAC Address): + +.dhcpreply table +|=== +|Identifier |Attribute |Op |Value |Context + +|`02:01:aa:bb:cc:dd` |`DHCP-Log-Server` |`:=` |`192.0.2.10` |`by-mac` +|`02:01:aa:bb:cc:dd` |`DHCP-LPR-Server` |`:=` |`192.0.2.11` |`by-mac` +|`02:01:aa:bb:cc:dd` |`Fall-Through` |`:=` |`Yes` |`by-mac` +|=== + +"dhcpgroup" maps identifiers to a group of options that can be shared: + +.dhcpgroup table +|=== +|Identifier |GroupName |Priority |Context + +|`02:01:aa:bb:cc:dd` |`salesdept` |`10` |`by-mac` +|=== + +"dhcpgroupreply" contains reply options for each group: + +.dhcpgroupreply table +|=== +|GroupName |Attribute |Op |Value |Context + +|`salesdept` |`DHCP-NTP-Servers` |`:=` |`192.0.2.20` |`by-mac` +|`salesdept` |`DHCP-Log-Server` |`+=` |`192.0.2.21` |`by-mac` +|`salesdept` |`DHCP-LPR-Server` |`^=` |`192.0.2.22` |`by-mac` +|=== + +Within the context of assigning options directly to devices, as well as to +manually-curated groups of devices keyed by their MAC address: + + - Place device-specific options in the "dhcpreply" table. + - Add `Fall-Through := Yes` to the options in the "dhcpreply" table in order + to trigger group lookups, which are disabled by default. + - Place entries in the "dhcpgroup" `identifier = <MAC-Address>, groupname = <group>, priority = + <priority>` in the "dhcpgroup" table to map a device to its groups by + priority. + - Place the grouped options in the "dhcpgroupreply" table. + - For each of the above, set `Context` to something by which the option + lookup is referred to in the policy, for example `Context = 'by-mac'`. + +For the above example you would add the following to the DHCP virtual server to +perform reply option lookup using the device's MAC address against the `by-mac` +context: + +[source,unlang] +---- +update control { + &DHCP-SQL-Option-Context := "by-mac" + &DHCP-SQL-Option-Identifier := &request:DHCP-Client-Hardware-Address +} +dhcp_sql.authorize +---- + +In the above, the DHCP reply options would be assigned to a device with MAC +address 02:01:aa:bb:cc:dd as follows: + + - Firstly, the `DHCP-Log-Server` option would be set to `192.0.2.10` and the + `DHCP-LPR-Server` option set to `192.0.2.11`. + - `Fall-Through` is set, so the group mapping is then queried which + determines that the device belongs to a single `salesdept` group. + - Finally, the options for the `salesdept` group are now merged, setting a + `DHCP-NTP-Servers` option to `192.0.2.20`, appending an additional + `DHCP-Log-Server` option set to `192.0.2.21`, and prepending an additional + `DHCP-LPR-Server` option set to `192.0.2.22`. + +If instead you wanted to perform a "subclass" lookup based on the first three +octets of the device's MAC address then with tables containing the following +sample data you could invoke an SQL lookup as shown: + +."dhcpreply" table: +|=== +|Identifier |Attribute |Op |Value |Context + +|`000393` |`Fall-Through` |`:=` |`Yes` |`class-vendor` +|`000a27` |`Fall-Through` |`:=` |`Yes` |`class-vendor` +|`f40304` |`Fall-Through` |`:=` |`Yes` |`class-vendor` +|=== + +."dhcpgroup" table: +|=== +|Identifier |GroupName |Priority |Context + +|`000393` |`apple` |`10` |`class-vendor` +|`000a27` |`apple` |`10` |`class-vendor` +|`f40304` |`google` |`10` |`class-vendor` +|=== + +."dhcpgroupreply" table: +|=== +|GroupName |Attribute |Op |Value |Context + +|`apple` |`DHCP-Boot-Filename` |`:=` |`apple.efi` |`class-vendor` +|`google` |`DHCP-Boot-Filename` |`:=` |`google.efi` |`class-vendor` +|=== + + +[source,unlang] +---- +update control { + &DHCP-SQL-Option-Context := "class-vendor" + &DHCP-SQL-Option-Identifier := \ + "%{substring:%{hex:&DHCP-Client-Hardware-Address} 0 6}" +} +dhcp_sql.authorize +---- + +The file `policy.d/dhcp` contains a policy named `dhcp_policy_sql` which +provides further worked examples for different types of option lookups. + +=== Testing "device", "class" and "group" options + +You should now test that any device-related options that you have configured +using the various methods available are applied successfully by generating +packets containing those parameters based upon which the reply options are set. + +For example, to test the iPXE user class example above you might want to +generate a request as follows: + +[source,shell] +---- +cat <<EOF > dhcp-packet-ipxe-boot.txt +DHCP-Message-Type := DHCP-Discover +DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd +DHCP-User-Class := "iPXE-class-abc" +EOF +---- + +To which you would expect to see a response such as: + +.Example output from dhcpclient +=============================== + dhcpclient: ... + ---------------------------------------------------------------------- + Waiting for DHCP replies for: 5.000000 + ---------------------------------------------------------------------- + ... + DHCP-Message-Type = DHCP-Offer + DHCP-Your-IP-Address = 1.2.3.4 + DHCP-Boot-Filename := "http://my.web.server/boot_script.php" + ... +=============================== diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_access.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_access.adoc new file mode 100644 index 0000000..40b8e30 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_access.adoc @@ -0,0 +1,54 @@ +== Configure access restrictions for pools + +We can combine what we have learned in the preceeding sections to provide pools +whose access is restricted in some way, for example to a particular class. + +Consider the ISC DHCP configuration snippet: + +[source,iscdhcp] +---- +subnet 10.99.99.0 netmask 255.255.255.0 { + pool { + range 10.99.99.200 10.99.99.250; + allow members of "printers"; + } + option routers 10.99.99.1; +} +---- + +Or the equivalent Kea configuration: + +[source,isckea] +---- +"Dhcp4": { + "subnet4": [{ + "subnet": "10.99.99.0/24", + "pools": [ + { + "pool": "10.99.99.200 - 10.99.99.250", + "client-class": "printers" + } + ], + "option-data": [ + { "name": "routers", "data": "10.10.0.1" } + ] + }], + ... +} +---- + +These define a subnet containing a single pool that is restricted to members of +the "printers" class. (The definition for this class is omitted.) + +In FreeRADIUS, to filter access to this pool entries such as the following +should included in the `<raddb>/mods-config/files/dhcp` configuration file: + +[source,config] +---- +network DHCP-Network-Subnet < 10.99.99.0/24, \ + DHCP-Group-Name == "printers", Pool-Name := "printers-pool" + DHCP-Router-Address := 10.99.99.1 +---- + +Note that any number of additional filters can be added to the initial "check" +line to restrict matches to the network block. diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_creation.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_creation.adoc new file mode 100644 index 0000000..e976873 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_ippool_creation.adoc @@ -0,0 +1,112 @@ +=== Determine the IP pool plan + +Except for cases where all IP allocation is performed using a mapping from the +device MAC address to a fixed IP address, the DHCP configuration will involve +the use of one or more IP address pools. + +FreeRADIUS stores all the IP addresses in its pools in whichever database has +been chosen. An instance of the `sqlippools` module is used to manage all pools +within a single table (normally `dhcpippool`). Each row of this table +corresponds to an IP address that is a member of some pool. The pools are +distinguished by name, so the table has a column (`pool_name`) that denotes +this. + +Each pool in this table should be composed of a set of equally valid IP +addresses for the devices that are designated to be members of the pool. + +Firstly, consider the network locations to which distinct ranges of IP +addresses must be allocated and provisionally assign a pool to each. + +Next, consider that many networks support multiple co-existing subnets without +VLAN separation. We will call this a "shared-network" to use the original ISC +DHCP parlance. In Microsoft DHCP contexts this is often referred to as a +"multinet". + +Often in a shared-network the policy has no regard for which of the network's +devices is allocated to which subnet. In this case we must create a single, +combined pool containing all of the IP addresses from each subnet in that +network. Since all addresses in a pool are treated equally this will mean that +any IP address may be allocated to a device that is making a DHCP request from +that network. The appropriate DHCP parameters for the subnet to which the IP +address belongs is determined after allocation. + +There are sometimes shared-networks (or even single subnets) for which IP +addresses belonging to any subnet may be technically suitable for any device, +however some local policy wants to assigning them to a particular subnet, for +example to provide loose segregation between classes of device. In this case we +define multiple pools, one for each range of IP addresses whose devices needs to +be differentiated. + +The choice of pool is ordinarily determined based on the network from which the +request originates using a mapping from Layer 2 networks to the pool name +provided by the user. The indicator for the originating network can be +overridden when this alone is insufficient to implement the required pool +selection policy such as when you need to differentiate the pool's users with +more granularity that their Layer 2 network, such as by considering device +attributes ("class" membership in ISC parlance) or Option 82 circuit data. + + +=== Populate the IP Pools + +By this stage you should have derived a list of pools, the IP address ranges +contained therein, and the means of selecting the pool to use based on the +originating network and/or some additional criteria from the request. + +A helper Perl script is provided with FreeRADIUS that can be used to populate +the pools provide that you are using the default schema. + +[source,shell] +---- +rlm_sqlippool_tool -p <pool_name> -s <range_start> -e <range_end> \ + -t <table_name> (-d <sql_dialect> | -f <raddb_dir> [ -i <instance> ]) \ + [ -c <capacity> ] [ -x <existing_ips_file> ] +---- + +If, for example, you had a range configured in ISC DHCP as: + +[source,iscdhcp] +---- +range 10.0.0.5 10.0.0.199 +---- + +and you are using PostgreSQL as your database, and you wish to refer to this pool +using the name `local`, this could be prepared with: + +[source,shell] +---- +rlm_sqlippool_tool -p local -s 10.0.0.5 -e 10.0.0.199 -t dhcpippool -d postgresql +---- + +If the SQL module of FreeRADIUS is already configured then this can +be referenced so that the tool is able to use the configured connection +parameters to connect to the database and populate the pool: + +[source,shell] +---- +rlm_sqlippool_tool -p local -s 10.0.0.5 -e 10.0.0.199 -t dhcpippool -f /etc/raddb +---- + +For installations that require multiple pools, `rlm_sqlippool_tool` can +be called referencing a YAML file defining the pools. Comments at the +head of `rlm_sqlippool_tool` explain the options in more detail. + +If static leases are required then these should be set up in the database +such that the MAC address of the client should be set as the `pool_key` +against the corresponding address and the `status` column of the row +representing the address set to `static`. A helper perl script, +`rlm_iscfixed2ippool` can be used to read an ISC DHCP config file and produce +SQL to perform these changes or directly update the database: + +[source,shell] +---- +rlm_iscfixed2ippool -c <dhcpd.<raddb> -t <table_name> -k <mac|id> \ + (-d <sql_dialect> | -f <raddb_dir> [-i <instance>]) +---- + +For example, to read /etc/dhcp/dhcpd.conf and populate the configured +FreeRADIUS database, using the mac as the identifier: + +[source,shell] +---- +rlm_iscfixed2ippool -c /etc/dhcp/dhcpd.conf -t dhcpippool -k mac -f /usr/local/etc/raddb +---- diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_network_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_network_options.adoc new file mode 100644 index 0000000..e2657a8 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_network_options.adoc @@ -0,0 +1,237 @@ +== Configure network-specific options and IP pool selection + +In an environment where multiple networks (often VLANs) are in use, it is +necessary to identify which network a client belongs to in order to assign an +address from the correct pool. + +Consider the ISC DHCP configuration snippet: + +[source,iscdhcp] +---- +option domain-name "example.org"; + +subnet 10.10.0.0 netmask 255.255.0.0 { + range 10.10.1.10 10.10.10.254; + range 10.10.100.10 10.10.110.254; + option routers 10.10.0.1; + option domain-name-servers 10.10.0.2, 10.10.0.3; + default-lease-time 7200; +} +---- + +Or the equivalent Kea configuration: + +[source,isckea] +---- +"Dhcp4": { + "option-data": [ + { "name": "domain-name", "data": "example.org" } + ], + "subnet4": [{ + "subnet": "10.10.0.0/16", + "pools": [ { "pool": "10.10.1.10 - 10.10.10.254" }, + { "pool": "10.10.100.10 - 10.10.110.254" } + ], + "option-data": [ + { "name": "routers", "data": "10.10.0.1" }, + { "name": "domain-name-servers", "data": "10.10.0.2, 10.10.0.3" } + ], + "valid-lifetime": 7200 + }], + ... +} +---- + +These define a network consisting of a single subnet 10.10.0.0/16 containing two +IP address pools 10.10.1.10 - 10.10.10.254 and 10.10.100.10 - 10.10.110.254. +Requests that are determined to have originated from this network (e.g. because +their `giaddr` belongs within the subnet) will be assigned the specified DHCP +parameters and allocated an address from one of its ranges. + +To provide equivalent functionality, FreeRADIUS must identify the correct DHCP +reply parameters as well as the name of the pool to be used for IP address +assignment, based on the originating network of the request. + +The definition for this pool (the addresses contained within it, corresponding +to the `range` statement in ISC DHCP and Kea) is specified entirely in the +database: It is precisely the rows in the `dhcpippool` table with a particular +`pool_name`. + +[TIP] +==== +As described previously, in FreeRADIUS a pool is a set of IP addresses that are +equally valid with respect to the network policy; therefore, unlike ISC DHCP +and ISC Kea, FreeRADIUS does not differentiate between the two `range`s. +Instead we should have previously populated a single pool containing all of the +IP addresses from both ranges. +==== + +FreeRADIUS derives a request attribute called `DHCP-Network-Subnet` which +honours the standard DHCP process for designating the choice of network, in +order of preference: + + 1. Link Selection Suboption of Option 82 + 2. IPv4 Subnet Selection Option + 3. Gateway IP Address ("giaddr") + 4. Client IP Address ("ciaddr", only set for unicast packets) + +If `DHCP-Network-Subnet` contains an IP address then this should be used as +the basis of choosing a network. When there is no address in this attribute it +can be assumed that the packet has been received from a client on the local +LAN. + +The `files` module in FreeRADIUS provides a simple method to map +`DHCP-Network-Subnet` to the corresponding pool based on its network +membership, setting the appropriate options to return to clients. It can also +set the global options. + +[TIP] +==== +In the case where an instance of the `files` module is used to get global +default parameters, the `dhcp_common` policy becomes redundant so the +statement calling the policy (by name) can be commented out in +`<raddb>/sites-enabled/dhcp`. +==== + +To use the provided example `files` module instance for DHCP, symlink or copy +`<raddb>/mods-available/dhcp_files` into `<raddb>/mods-enabled/` and then +uncomment the calls to `dhcp_network` in `<raddb>/sites-enabled/dhcp`. + +A template configuration file `<raddb>/mods-config/files/dhcp` is also +provided which should be adapted to suit your network topology. + +For the configuration above you may deduce the following configuration, which +has been extended to include an initial default section for requests originating +from directly-connected clients on the local LAN (192.168.20/24): + +[source,config] +---- +network Pool-Name := "local" + DHCP-Domain-Name := "example.org", + DHCP-Subnet-Mask := 255.255.255.0, + DHCP-Router-Address := 192.168.20.1, + DHCP-Domain-Name-Server := 192.168.20.2, + Fall-Through := yes + +network DHCP-Network-Subnet < 10.10.0.0/16, Pool-Name := "remote" + DHCP-Subnet-Mask := 255.0.0.0, + DHCP-Router-Address := 10.10.0.1, + DHCP-Domain-Name-Server := 10.10.0.2, + DHCP-Domain-Name-Server += 10.10.0.3, + DHCP-IP-Address-Lease-Time := 7200 +---- + +Each block in the file starts with a line beginning with the key to be matched. +In this case the keyword of `network` (defined earlier in `dhcp_networks` +configuration) is used for each block, so each of the above blocks is a +candidate during the search. + +There may be further filtering of the candidates in the form of `<Attribute> +<op> <Value>`. In the case of the second block we match the +`DHCP-Network-Subnet` to an enclosing subnet with +`DHCP-Network-Subnet < <subnet>`. Additional filters could be added as +required, comma separated. + +Following the filters on the first line, attributes in the `control` list can +be set using the syntax of `<Attribute> := <Value>`. In this example this is +used to specify the `Pool-Name` for choosing the appropriate IP pool to +allocate an address from. + +Subsequent indented lines are attribute assignments for values in the `reply` +list. Note that, apart from the last line, they are all terminated with a +comma. + +The special option `Fall-Through` determines whether, following a match, +other records are checked for a match. All lookups will match the entry +with a key of `network` and no further filtering, so `Fall-Through` +is set on that record in order that the other records will be tested +to find subnet matches. + +=== Example packet processing + +For our example, we consider a request arriving from a DHCP relay within +10.10.0.0/16. In the absence of any specific DHCP subnet selection options in +the request, the `DHCP-Network-Subnet` attribute is calculated to be the +relay's IP address, say 10.10.0.1. + +The request is matched against the first block, setting an initial pool name to +"local", domain name to "example.org" and setting some additional global +default parameters. By virtue of `Fall-Through` being set, the next block is +considered. + +Since the network identifier is within the specified subnet (i.e. `10.10.0.1 < +10.10.0.0/16`) this second block is matched. This block overrides the pool name +setting it to "remote", overrides some other global defaults and sets the lease +time to 7200 seconds. `Fall-Through` is not set, so we are now done with +deriving the pool name and network options. + +When the `dhcp_sqlippool` module is called during DHCP DISCOVER processing (in +`<raddb>/sites-enabled/dhcp`) the `remote` pool will be used for IP address +allocation. + +The assigned IP address and network parameters will subsequently be returned in +the DHCP reply. + +=== Testing the pool operation and network-specific options + +Before proceeding further, you should test the operation of the IP pools and +ensure that any network-specific reply attributes that you have configured are +correctly set in replies. + +For example, if you have a single, flat pool you should test using sample +packets for devices with different MAC addresses and/or Client Identifiers. + +[source,shell] +---- +cat <<EOF > dhcp-packet-1.txt +DHCP-Message-Type := DHCP-Discover +DHCP-Client-Hardware-Address := 02:01:11:11:11:11 +DHCP-Client-Identifier := device1 +EOF +---- + +[source,shell] +---- +cat <<EOF > dhcp-packet-2.txt +DHCP-Message-Type := DHCP-Discover +DHCP-Client-Hardware-Address := 02:01:22:22:22:22 +DHCP-Client-Identifier := device2 +EOF +---- + +Generate these packets as show previously using the dhcpclient tool and look +for `DHCP-Your-IP-Address` in the DHCP responses to determine the IP address +that has been offered. + +Ensure that the DHCP Offer responses contain unique IP addresses. Ensure that +when these requests are resent within the lifetime of the initial offer that +the reponses to the subsequent replies contain the original IP address that was +in the initial offer to the device. + +Additionally, ensure that the DHCP Offers contain any network-specific +parameters that you have specified. + +In the case that the policy contains multiple IP pools and network definitions +for clients belonging to different Layer 2 networks (or indeed belonging to the +same network but segregated according to some local policy) you should ensure +that the devices are being mapped to the correct definition. + +For a typical policy that selects the IP pool and network options based on the +originating network for the DHCP packet, explicitly specifying a network by +including a `DHCP-Subnet-Selection-Option` parameter may avoid the need to test +from a host within each individual network: + +[source,shell] +---- +cat <<EOF > dhcp-packet-network-10.10.10.0.txt +DHCP-Message-Type := DHCP-Discover +DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd +DHCP-Client-Identifier := abc123 +DHCP-Subnet-Selection-Option := 10.10.10.0 +EOF +---- + +For policies where the IP pool and network option selection is based on some +custom criteria it is necessary to include different variations for the +parameters on which the policy makes the decision. The testing example for the +class-specific options later in this document provides such an example. diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/policy_subnet_options.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/policy_subnet_options.adoc new file mode 100644 index 0000000..1980e89 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/policy_subnet_options.adoc @@ -0,0 +1,184 @@ +== Configure subnet-specific options for shared networks + +In the case that shared-networks are in use, with the pool containing +equally-valid IP addresses from multiple subnets, it is necessary to set the +subnet-specific parameters such as `DHCP-Router-Address`, `DHCP-Subnet-Mask` +and `DHCP-Broadcast-Address` based on the IP address that has been allocated. + +Consider the ISC DHCP configuration snippet: + +[source,iscdhcp] +---- +option domain-name "example.org"; + +shared-network bigdept { + + option domain-name-servers 10.10.0.2, 10.10.0.3; + default-lease-time 7200; + + subnet 10.30.10.0 netmask 255.255.255.0 { + option routers 10.30.10.1; + } + subnet 10.30.20.0 netmask 255.255.255.0 { + option routers 10.30.20.1; + } + range 10.30.10.10 10.30.10.254; + range 10.30.20.10 10.30.20.254; + +} +---- + +Or the equivalent Kea configuration: + +[source,kea] +---- +"Dhcp4": { + "option-data": [ + { "name": "domain-name", "data": "example.org" } + ], + "shared-networks": [{ + "name": "bigdept", + "option-data": [ + { "name": "domain-name-servers", "data": "10.10.0.2, 10.10.0.3" } + ], + "valid-lifetime": 7200, + "subnet4": [{ + "subnet": "10.30.10.0/24", + "pools": [ { "pool": "10.30.10.10 - 10.30.10.254" } ], + "option-data": [ + { "name": "routers", "data": "10.30.10.1" } + ] + }], + "subnet4": [{ + "subnet": "10.30.20.0/24", + "pools": [ { "pool": "10.30.20.10 - 10.30.20.254" } ], + "option-data": [ + { "name": "routers", "data": "10.30.20.1" } + ] + }] + }], + ... +} +---- + +As with the network to pool lookup, an instance of the `files` modules can be +employed (this time after the allocation of an IP address) to set the correct +reply parameters based on the subnet membership of the assigned address. + +To do this, we can use this section of `<raddb>/mods-available/dhcp_files`: + +[source,config] +---- +files dhcp_subnets { + filename = ${modconfdir}/files/dhcp + key = "subnet" +} +---- + +Additionally, uncomment the `dhcp_subnets` policy in `<raddb>/policy.d/dhcp`. +This policy wraps the call to the `dhcp_subnets` files module with code that +"tightens" the `DHCP-Network-Subnet` attribute by setting it to the +just-allocated IP address. + +The relevant entries in the `<raddb>/mods-config/files/dhcp` configuration +file might then look something like this: + +[source,config] +---- +network + DHCP-Domain-Name := "example.org", + Fall-Through := yes + +network DHCP-Network-Subnet < 10.30.0.0/16, Pool-Name := "bigdept" + DHCP-Domain-Name-Server := 10.10.0.2, + DHCP-Domain-Name-Server += 10.10.0.3, + DHCP-IP-Address-Lease-Time := 7200 + +subnet DHCP-Network-Subnet < 10.30.10.0/24 + DHCP-Router-Address := 10.30.10.1 + +subnet DHCP-Network-Subnet < 10.30.20.0/24 + DHCP-Router-Address := 10.30.20.1 +---- + +=== Example packet processing + +For our example, we consider a request arriving from a DHCP relay within +10.30.10.0/24. In the absence of any specific DHCP subnet selection options in +the request, the `DHCP-Network-Subnet` attribute is calculated to be the +relay's IP address, say 10.30.10.1. + +The request is matched against the first "network" block, setting the domain +name to "example.org". By virtue of `Fall-Through` being set, the next "network" +block is considered. + +Since the network identifier is within the specified subnet (i.e. `10.30.10.1 < +10.30.0.0/16`) this second "network" block is matched. This block sets the pool +name to "bigdept", sets some network-specific DNS resolvers and sets the lease +time to 7200 seconds. `Fall-Through` is not set, so we are now done with +deriving the pool name and network options. + +When the `dhcp_sqlippool` module is called during DHCP DISCOVER processing (in +`<raddb>/sites-enabled/dhcp`) the `bigdept` pool will be used for IP address +allocation. + +After IP allocation the `dhcp_subnet` policy and files instance are called. +Before the subnet options are looked up the `DHCP-Network-Subnet` +attribute is tightened to match the assigned IP address, say 10.30.20.123. + +The request does not match the first subnet block since 10.30.20.123 is not +within 10.30.10.0/24. However, the request does match the second subnet block +since `10.30.20.123 < 10.30.20.0/24`. This block sets the default gateway +reply parameter. `Fall-Through` is not set, so we are now done with deriving +the pool name and network options. + +The assigned IP address, network and subnet parameters will subsequently be +returned in the DHCP reply. + +=== Testing the subnet-specific options + +If you have set any subnet-specific reply parameters then you should test these +before proceeding further. + +For example, in the case that you have a single, large pool spanning two IP +subnets you might want to test by repeatedly allocating addresses using sample +packets with different MAC addresses, each time checking to ensure that the +DHCP parameters correspond to the IP address that has been offered. + +.Example output from dhcpclient showing a response +================================================== + dhcpclient: ... + ... + ---------------------------------------------------------------------- + Waiting for DHCP replies for: 5.000000 + ---------------------------------------------------------------------- + ... + DHCP-Your-IP-Address = 10.0.10.50 + DHCP-Router-Address = 10.0.10.1 + DHCP-Broadcast-Address = 10.0.10.255 + DHCP-Subnet-Mask = 255.255.255.255 +================================================== + + +.Example output from dhcpclient showing a response +================================================== + dhcpclient: ... + ... + ---------------------------------------------------------------------- + Waiting for DHCP replies for: 5.000000 + ---------------------------------------------------------------------- + ... + DHCP-Your-IP-Address = 10.99.99.50 + DHCP-Router-Address = 10.99.99.1 + DHCP-Broadcast-Address = 10.99.99.255 + DHCP-Subnet-Mask = 255.255.255.255 +================================================== + + +[TIP] +==== +If the subnets are large then you might want to temporarily reduce their +size by setting the `status` field of the majority of the rows for each subnet +to "`disabled`" to cause offers to be made more readily with IP addresses in +different subnets. +==== diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/prepare.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/prepare.adoc new file mode 100644 index 0000000..aa43530 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/prepare.adoc @@ -0,0 +1,59 @@ +== Preparation + +It is necessary to consider the requirements for the installation in order to +devise an efficient and manageable set up. + +=== Understand the network topology + +When multiple networks (VLANs) are in use consideration must be given to how +the correct "pool" (IP address ranges) from which to allocate addresses is +identified. + +The policy for setting specific DHCP options (e.g. lease time, default gateway, +time server and vendor-specific parameters) for different groups of hosts, +based on their network or some device attributes either supplied in the DHCP +requests or determined by dynamic lookup, should be well defined and +understood. + +Other DHCP servers may implement implicit assumptions about the requirement of +your network topology and silently define particular behaviours, such as the +selection of IP address pool for a request based on a relay address. Some of +these behaviours must be specifed explicitly when using FreeRADIUS. + +=== Choose a database backend + +FreeRADIUS stores its leases in an SQL database, so one of the key decisions to +make is which database to use. + +FreeRADIUS supports: + + * SQLite + * PostgreSQL + * MySQL / MariaDB + * Microsoft SQL Server + * Oracle + +In most configurations the SQL database is likely to be the limiting component +that restricts the IP allocation throughput of the overall system. Each +database server has its own performance characteristics and unique approach to +features such as high-availability. + +The choice of database should be made carefully based on the performance and +high-availability requirements of the system, as well as any prior experience. + +[TIP] +==== +SQLite is an in-process database that uses the local file system, is simple to +configure and is suitable for smaller installations. However, users with larger +address pools or high availability requirements should choose one of the other +standalone databases based on criteria such as performance, features, +familiarity and your need for commercial support. +==== + +FreeRADIUS ships with a default database schema and set of queries for each +supported database. These are sufficient for most DHCP deployments but can be +reviewed and modified as required to suit a particular situation, for example +to customise the IP allocation policy such as by disabling address +"stickiness". + +Now xref:protocols/dhcp/enable.adoc[enable the DHCP service]. diff --git a/doc/antora/modules/howto/pages/protocols/dhcp/test.adoc b/doc/antora/modules/howto/pages/protocols/dhcp/test.adoc new file mode 100644 index 0000000..322de08 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/dhcp/test.adoc @@ -0,0 +1,143 @@ +== Testing the DHCP service + +We can verify that FreeRADIUS is providing a DHCP service using the +`dhcpclient` tool that is included with the FreeRADIUS distribution. + +Temporarily configure FreeRADIUS to issue a single static IP address to all +clients by updating the `dhcp DHCP-Discover` section in the `dhcp` virtual +server to include the following: + +[source,unlang] +---- +update reply { + &DHCP-Your-IP-Address := 1.2.3.4 +} +---- + +Define a sample DHCP packet as follows: + +[source,shell] +---- +cat <<EOF > dhcp-packet.txt +DHCP-Message-Type := DHCP-Discover +DHCP-Client-Hardware-Address := 02:01:aa:bb:cc:dd +DHCP-Client-Identifier := abc123 +EOF +---- + +We can now generate this packet by invoking one of the following commands based +on the current circumstances... + +From the host that is running the FreeRADIUS DHCP server: + +[source,shell] +---- +dhcpclient -i lo 255.255.255.255 -f dhcp-packet.txt -x auto +---- + +From a different host with an interface (eth0) in the same broadcast domain +as the FreeRADIUS DHCP server: + +[source,shell] +---- +dhcpclient -i eth0 255.255.255.255 -f dhcp-packet.txt -x auto +---- + +If all of the DHCP broadcast traffic in other Layer 2 networks is converted to +unicast by DHCP relay agents then it is not necessary for FreeRADIUS to listen +on a broadcast address. In this case you can test DHCP using a unicast request: + +[source,shell] +---- +dhcpclient 192.0.2.10 -f dhcp-packet.txt -x auto +---- + +[NOTE] +==== +In order for the returned, unicast DHCP OFFER to be received it is necessary to +ensure that the `DHCP-Your-IP-Address` parameter set by FreeRADIUS matches an +address on the interface used by the dhcpclient tool to send the Discover +packet. +==== + +When one of the above commands is run, the tool with generate output such as +the following which shows that the packet was sent and that it is now waiting +for replies: + +.Example output from dhcpclient showing the request +=================================================== + dhcpclient: ... + ---------------------------------------------------------------------- + DHCP-Opcode = 0x01 + DHCP-Hardware-Type = 0x01 + DHCP-Hardware-Address-Length = 0x06 + DHCP-Hop-Count = 0x00 + DHCP-Transaction-Id = 0x5e0bbfab + DHCP-Number-of-Seconds = 0x0000 + DHCP-Flags = 0x0000 + DHCP-Client-IP-Address = 0x00000000 + DHCP-Your-IP-Address = 0x00000000 + DHCP-Server-IP-Address = 0x00000000 + DHCP-Gateway-IP-Address = 0x00000000 + ... + ---------------------------------------------------------------------- + Waiting for DHCP replies for: 5.000000 + ---------------------------------------------------------------------- +=================================================== + + +Each received DHCP response will generate output such as the following: + +.Example output from dhcpclient showing a response +================================================== + ... + ---------------------------------------------------------------------- + DHCP-Opcode = Server-Message + DHCP-Hardware-Type = Ethernet + DHCP-Hardware-Address-Length = 6 + DHCP-Hop-Count = 0 + DHCP-Transaction-Id = 1577828267 + DHCP-Number-of-Seconds = 0 + DHCP-Flags = 0 + DHCP-Client-IP-Address = 0.0.0.0 + DHCP-Your-IP-Address = 1.2.3.4 + DHCP-Server-IP-Address = 192.0.2.10 + DHCP-Gateway-IP-Address = 0.0.0.0 + DHCP-Client-Hardware-Address = 02:42:0a:00:00:0b + DHCP-Message-Type = DHCP-Offer + DHCP-Client-Identifier = 0x616263313233 + Waiting for additional DHCP replies for: 4.999429 + ... +================================================== + +Examine the DHCP response to ensure that it has the correct message type +(`DHCP-Offer`, in this case), contains the temporary IP address that you +configured earlier, i.e. `DHCP-Your-IP-Address = 1.2.3.4`, and any other +expected reply parameters (which we configure later). You should also carefully +examine the output of a FreeRADIUS debug session (`radius -X`) to ensure that +the policy is being executed in the way that you expect and that no warnings +are being generated. + +You can now change the content of the sample DHCP request by editing the +`dhcp-packet.txt` file and re-run the above command to see the server's reply. +You should examine the DHCP dictionary distrubuted with FreeRADIUS (usually +`/usr/share/freeradius/dictionary.dhcp`) which provides the list of all of the +DHCP parameters ("attributes") understood by FreeRADIUS. + +[WARNING] +==== +When you are done **remember** to remove the temporary edit that was made to +the `dhcp` virtual server that provides the static IP assignment. +==== + +=== Testing the DHCP policy + +The remainder of this guide describes how to configure the IP address plan, +setup the IP pools and define a DHCP policy. You should develop your policy by +making small, incremental changes to the provided configuration and then test +those changes with the approach described above, using `dhcpclient` and `radius -X`, +modifying the sample DHCP packet as required. If you break the policy then +revert the last change, attempt to understand what went wrong, and try +something else. + +Now xref:protocols/dhcp/policy.adoc[define the DHCP policy]. diff --git a/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc b/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc new file mode 100644 index 0000000..b689824 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/proxy/enable_proxy_protocol.adoc @@ -0,0 +1,114 @@ +== Enabling PROXY Protocol + +Now that we have a working configuration which used RadSec and HAproxy +or Traefik, we are finally ready to enable PROXY Protocol. + +Configure FreeRADIUS on the `radsecsvr` host to expect the PROXY +Protocol for RadSec connections. This is done by editing the `listen +{}` section of the `tls` virtual server to include a reference to the +proxy protocol: + +.Enabling PROXY Protocol in a FreeRADIUS virtual server +======================================================= + + listen { + ... + proxy_protocol = true + ... + } + +======================================================= + +Now restart the debugging session: +[source,shell] +---- +radiusd -fxxl /dev/stdout +---- + + +For HAproxy, you should enable the PROXY Protocol on connections to +the RadSec backend, by editing the `backend` definition to add a +`send-proxy` argument: + +.Example HAproxy backend configuration with PROXY Protocol +========================================================== + + backend radsec_be + mode tcp + balance roundrobin + server radsecsvr 172.23.0.3:2083 send-proxy + +========================================================== + +Note the `send-proxy` argument in the `server` definition. + +Now reload the HAproxy service: + +[source,shell] +---- +service haproxy reload +--- + + +For Traefik, enable the PROXY Protocol on connections to the RadSec +backend by editing the `radsec-service` definition to add a reference +to the proxy protocol" + +.Example Traefik service configuration with PROXY Protocol +========================================================== + + radsec-service: + loadBalancer: + servers: + - address: "172.23.0.3:2083" + proxyProtocol: + version: 1 + +========================================================== + +Note the `proxyProtocol` and `version: 1` directives. + +Traefik should automatically detect the updates and reconfigure the +service. + + +=== Testing RadSec connectivity via a proxy using PROXY Protocol + +Finally, with your test client configured to use the proxy, perform a +test authentication: + +[source,shell] +---- + echo "User-Name = bob" | radclient 127.0.0.1 auth testing123 +---- + +You should expect to see the familiar output: + +.Example output from radclient +============================== + + Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27 + Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39 + +============================== + +Now examine the FreeRADIUS debug output on the RadSec server: + +.Expected output from `radiusd -X` with PROXY Protocol +====================================================== + + ... + (0) (TLS) Received PROXY protocol connection from client \ + 172.23.0.2:55343 -> 172.23.0.4:2083, via proxy 172.23.0.4:40268 -> 0.0.0.0:2083 + ... + (0) Received Access-Request Id 227 from 172.23.0.2:55343 to 172.23.0.4:2083 length 49 + (0) Sent Access-Accept Id 227 from 172.23.0.4:2083 to 172.23.0.2:55343 length 0 + ... + +====================================================== + +The output indicates that FreeRADIUS is receiving the originating +connection information from the PROXY Protocol. FreeRADIUS then +handles the RadSec requests as though they have been received directly +from the originating client. + diff --git a/doc/antora/modules/howto/pages/protocols/proxy/enable_radsec.adoc b/doc/antora/modules/howto/pages/protocols/proxy/enable_radsec.adoc new file mode 100644 index 0000000..f5e7603 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/proxy/enable_radsec.adoc @@ -0,0 +1,188 @@ +== Enabling RadSec with FreeRADIUS + +Our first task is to set up a RadSec server by configuring an instance of +FreeRADIUS to accept RADIUS over TLS requests. + +The following steps should be performed on the host which will be the +RadSec server, we will call it `radsecsvr`. + +You can install FreeRADIUS using the NetworkRADIUS packages by +following the instructions provided here: + +<https://networkradius.com/packages/> + +Before making any configuration changes, you should stop the radiusd +service: + +[source,shell] +---- + service radiusd stop +---- + +Then, enable the `tls` virtual server: + +[source,shell] +---- +cd /etc/raddb/sites-enabled +ln -s ../sites-available/tls +---- + +The FreeRADIUS distribution contains an example Certificate Authority +that will have generated the necessary CA, server and client +certificates and keys during package installation. You can use this +CA, or you can use your own CA and certificates. + +[TIP] +==== +If the example certificates are not present (for example if FreeRADIUS was +installed from source) then FreeRADIUS will fail to start. The files can be +regenerated by running `make` in the `/etc/raddb/certs` directory. +==== + +Edit the `tls` virtual server configuration, in order to add +definitions for the clients by extending the `clients radsec {}` section: + +.Example radsec client definitions in `/etc/raddb/sites-available/tls` +==== + + clients radsec { + ... + # Direct connections from the test client + client radseccli { + ipaddr = 172.23.0.2 + proto = tls + virtual_server = default + } + # Connections via HAproxy + client haproxy { + ipaddr = 172.23.0.4 + proto = tls + virtual_server = default + } + # Connections via Traefik + client traefik { + ipaddr = 172.23.0.5 + proto = tls + virtual_server = default + } + } + +==== + +The client `ipaddr` configuration item is used to match the source IP +address of incoming connections. You must add client definitions for +each of the clients which will connect. + +For RadSec, you can just list the IP address of the RadSec client. +This client definition is used for processing RADIUS packets from the +RadSec client. + +[NOTE] +==== +A `secret` does not have to be specified for RadSec clients, as the +default is `radsec`. If you specify a secret, then that will be used +instead of `radsec`. +==== + +When the PROXY protocol is used, you must _also_ define a client which +matches the IP address of the proxy (haproxy, etc). This client is +only used to check that the source IP is permitted to connect to the +server. Fields other than `ipaddr` can be specified (and in some +cases may be required). However, all other fields will be ignored. + +For testing purposes, we want to amend the `default` virtual server so +that it accepts all authentication reqeusts and immediately responds +to accounting requests. + +Edit the `/etc/raddb/sites-enabled/default` file so that the beginning of +the `authorize` and `preacct` sections looks as follows: + +.Example default virtual server modification to unconditionally accept Access-Requests +==== + + authorize { + accept + ... + } + ... + preacct { + handled + ... + } + +==== + +This change makes the `authorize` section always "accept" the user, +and makes the `preacct` section always say "we handled the accounting +request". These changes are only for testing, and should never be +used in production. + +Start the FreeRADIUS service in the foreground with debugging enabled: + +[source,shell] +---- +radiusd -fxxl /dev/stdout +---- + +Examine the output from FreeRADIUS to ensure that it is now listening for +RadSec connection on TCP/2083: + +.Example output from running `radiusd -fxxl /dev/stdout` +==== + + FreeRADIUS Version 3.0.24 + Copyright (C) 1999-2021 The FreeRADIUS server project and contributors + ... + ... : Debug: Listening on auth+acct proto tcp address * port 2083 (TLS) bound to server default + ... : Debug: Listening on auth address * port 1812 bound to server default + ... : Debug: Listening on acct address * port 1813 bound to server default + ... : Debug: Listening on auth address :: port 1812 bound to server default + ... : Debug: Listening on acct address :: port 1813 bound to server default + ... + ... : Info: Ready to process requests + +==== + +FreeRADIUS is now ready to process RadSec traffic. + +For testing, we first test normal RADIUS over UDP functionality, then +the RadSec connection using a test client, then introduce a proxy +server, and finally we enable PROXY Protocol. Doing the tests in this +way ensures that we know that all previous steps work before trying +the next step. This process allows us to quickly narrow down +problems, and gets us to the final goal _faster_ than just "doing +everything all at once". + +=== Testing the RADIUS policy + +Before moving on, verify that the FreeRADIUS policy is able to +authenticate a local test RADIUS Access-Request over UDP: + +[source,shell] +---- +echo "User-Name = terry" | radclient 127.0.0.1 auth testing123 +---- + +Due to the `accept` we added in the `authorize` section, the expected +output should be an Access-Accept: + +.Expected output from radclient +=============================== + + Sent Access-Request Id 157 from 0.0.0.0:36850 to 127.0.0.1:1812 length 27 + Received Access-Accept Id 157 from 127.0.0.1:1812 to 127.0.0.1:36850 length 20 + +=============================== + +Any other output indicates that there is a problem with the FreeRADIUS +configuration which *must* be solved before testing RadSec. Carefully verify that +you have carried out each of the above steps correctly and examine the debug +output from FreeRADIUS, which will usually tell you what is wrong. + +See [how to read the debug +output](http://wiki.freeradius.org/radiusd-X) for instructions on +reading amd understanding the debug output. + +The next step is to xref:protocols/proxy/radsec_client.adoc[configure +FreeRADIUS as a RadSec test client] so that we can verify that our +RadSec server is working. diff --git a/doc/antora/modules/howto/pages/protocols/proxy/index.adoc b/doc/antora/modules/howto/pages/protocols/proxy/index.adoc new file mode 100644 index 0000000..5100635 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/proxy/index.adoc @@ -0,0 +1,126 @@ += Proxying RadSec and enabling PROXY Protocol + +This guide shows how to set up FreeRADIUS to serve RadSec connections, fronted +by either HAproxy or Traefik as Layer 4 proxies that pass on the original +client connection information using PROXY Protocol. + +It is not a comprehensive guide to using RadSec with FreeRADIUS. It presents a +basic configuration that uses an example CA and does not validate certificate +attributes or perform revokation status. + + +== Introduction + +FreeRADIUS supports receiving RADIUS requests over TLS-enabled TCP connections +and supports proxying of requests over TCP connections to another TLS-enabled +homeserver. The protocol for RADIUS over TLS is called "RadSec" and is defined +in RFC 6614. + +FreeRADIUS is a capable and performant application-aware ("Layer 7") proxy / +load-balancer for RadSec and other forms of RADIUS traffic. + + +=== Layer 4 proxying + +Rather than use an application-aware proxy it is sometimes better to reduce the +performance impact incurred by re-encoding an application protocol by using a +"Layer 4" proxy that operates at the level of individual connections without +regard for the application protocol. Such a proxy is more of a "bump in the +wire" than a request buffer and minimises the latency incurred due to proxying. + +It is common to see software such as HAproxy and Traefik used in Layer 4 mode +in place of FreeRADIUS for purposes such as connection load balancing. In +addition to improved performance, these tools have the benefit that they +typically support dynamic service discovery and "hitless" reloads to +automatically adapt their connection routing based on changes to backend +services such as the introduction of new nodes with even a momentary loss of +service. + + +=== Loss of connection information + +When TCP connections are relayed through Layer 4 proxies the information +about the originating source of the connection is no longer known to the +backend service, unless it is otherwise made available. Identifying the +originator of connections is often necessary for security purposes and for +request processing. + +Whilst many application protcols support headers that allow proxies to preserve +connection information these are not helpful in the context of Layer 4 +proxying: The process of populating headers requires knowledge of the +application protocol to re-encode requests as they are transmitted between the +frontend and backend connections. + + +=== PROXY Protocol + +PROXY Protocol overcomes this limitation by allowing the original connection +information to be provided to the backend at the start of the TCP connection. +After this initial data is encoded the remainder of the conversation then +proceeds as normal. However now that the connection information is known to the +backend server it is able to process requests made on the connection as though +the connection were being made directly by the client and not via the proxy. + +PROXY Protocol is specified in this document: +http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt + + +== Requirements + +PROXY Protocol Version 1 is supported by FreeRADIUS v3.0.24 and later versions. + +You will require the following set of VMs or containers, each with their own +IP address: + +[cols="1,1,1"] +|=== +|Hostname|IP address|Purpose + +|radseccli +|172.23.0.2 +|FreeRADIUS configured to provide a RadSec test client + +|radsecsvr +|172.23.0.3 +|FreeRADIUS configured as a RadSec server + +|haproxy +|172.23.0.4 +|HAproxy in Layer 4 mode to the FreeRADIUS RadSec backend +|=== + +Optionally you may want to configure a host to run Traefik within a Docker +container using host mode networking, perhaps configured by Docker Compose, +however the installation is beyond the scope of this guide: + +[cols="1,1,1"] +|=== +|traefik +|172.23.0.5 +|Traefik configured as a TCP router with TLS passthrough to the FreeRADIUS RadSec backend +|=== + +The hostnames and IP addresses provided above are for examples purposes and are +used throughout the remainder of this guide. This guide provides commands and +output for CentOS. Other distributions will have minor differences, including +the location of the FreeRADIUS configuration (the "raddb"). + +[NOTE] +==== +You can choose to use your own hostname, IP addresses and OS distribution. You +could also use official Docker images provided by the respecitive projects, +however these prescribe methods for configuring and managing the services +that are not typical for a normal package installation which would provide a +distraction if used for by guide. +==== + + +== Sections in this guide + +This guide is organised into four parts that should be read in order: + +1. xref:protocols/proxy/enable_radsec.adoc[Enabling RadSec] +2. xref:protocols/proxy/radsec_client.adoc[Configuring a test RadSec client] +3. xref:protocols/proxy/radsec_with_haproxy.adoc[Proxying RadSec with HAproxy] +4. xref:protocols/proxy/radsec_with_traefik.adoc[Proxying RadSec with Traefik] +5. xref:protocols/proxy/enable_proxy_protocol.adoc[Enabling PROXY Protocol for RadSec] diff --git a/doc/antora/modules/howto/pages/protocols/proxy/radsec_client.adoc b/doc/antora/modules/howto/pages/protocols/proxy/radsec_client.adoc new file mode 100644 index 0000000..d92345e --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/proxy/radsec_client.adoc @@ -0,0 +1,181 @@ +== Configuring FreeRADIUS as a RadSec test client + +Unfortunately, the `radclient` program does not support RadSec. We +must therefore configure an instance of FreeRADIUS as a "transport +converter" which proxies UDP-based RADIUS requests to a RadSec +destination of our choice. + +The following steps should be performed on a client system, which we +will call `radseccli`. This system should be a new system, with a +different IP address. That is, you shoudl not edit the configuration +on the `radsecsvr` host. Doing so will break the RadSec configuration. + +Install FreeRADIUS using the NetworkRADIUS packages by following the +instructions provided here: + +<https://networkradius.com/packages/> + +Before making any configuration changes, you should stop the radiusd +service: + +[source,shell] +---- + service radiusd stop +---- + +Add a new `tls` home server definition, which will point to the RadSec +server. We do this by creating a file +`/etc/raddb/sites-enabled/radsec-homeserver` with the following +contents: + +.Example homeserver, pool and realm definitions for the RadSec service +==== + + home_server tls { + ipaddr = 172.23.0.3 # IP address of our RadSec server + port = 2083 + type = auth+acct + proto = tcp + tls { + private_key_password = whatever + private_key_file = ${certdir}/client.pem + certificate_file = ${certdir}/client.pem + ca_file = ${cadir}/ca.pem + } + } + home_server_pool tls { + type = fail-over + home_server = tls + } + realm tls { + auth_pool = tls + acct_pool = tls + } + +==== + +[TIP] +==== +Complete descriptions of each of the above configuration items can be found in the +`[raddb]/sites-available/tls` example configuration file. For simple tests, however, +we can omit all of the comments from the file. +==== + +To use this `tls` home server, we change the `default` virtual server to proxy +all authentication and accounting requests to it. + +Edit the `/etc/raddb/sites-enabled/default` file so that the beginning of +the `authorize` and `preacct` sections looks as follows: + +.Example default virtual server modification to proxy requests to a RadSec proxy server +==== + + authorize { + update control { + &Proxy-To-Realm := tls + } + handled + ... + } + ... + preacct { + update control { + &Proxy-To-Realm := tls + } + handled + ... + } + +==== + +These changes make the `tls` virtual server always proxy packets. +These changes are only for testing, and should never be used in +production. + +We must now copy the example CA certificate as well as the client +certificate and key files which are on the `radsecsrv` host to this +test client. + +Replace the following files on `radseccli` with the equivalent files from +`radsecsrv`: + +[cols="1,1,1"] +|=== +|File|Corresponding configuration item|Purpose + +|/etc/raddb/certs/ca.pem +|`ca_file` +|CA certificate which is used to authenticate the server certificate presented by the RadSec server to the client. + +|/etc/raddb/certs/client.pem +|`certificate_file` +|Client certificate (signed by the CA certificate) that is presented by the test client to the RadSec server. + +|/etc/raddb/certs/client.pem +|`private_key_file` and `private_key_password` +|Private key corresponding to the client certificate +|=== + +Note that the client certificate and key are typically bundled into a single file. + +[CAUTION] +==== +If you do not correctly replace the CA, client certificate, and key +material on the test client then the RadSec client and RadSec server +will fail to mutually authenticate each other as they do not share a +trusted CA. If you see messages like `unknown CA`, then you know that +the certificates have not been set up correctly. +==== + +Start the FreeRADIUS service in debug mode: + +[source,shell] +---- +radiusd -X +---- + + +=== Testing RadSec connectivity + +At this stage you should be able to cause the test client to send RadSec +requests directly to the RadSec server. + +Run the following to send a RADUS (UDP) Access-Request to the local FreeRADIUS +instance. It should then proxy the request over RadSec connection to +the remote RadSec server: + +[source,shell] +---- + echo "User-Name = bob" | radclient 127.0.0.1 auth testing123 +---- + +If the test client is able to successfully establish the RadSec +connection, and the RadSec server replies with an Access-Accept +response, then the output will be as follows: + +.Expected output from radclient +=============================== + + Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27 + Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39 + +=============================== + +Lack of response or an Access-Reject response indicates that the RadSec +connection is not being established successfully. + +There may be serveral reasons for broken connectivity including: + + * The client not accepting the certificate presented by the server. + * The server not accepting the certificate presented by the client. + +Look at the debug output generated by both the test client and the RadSec +server. In many cases it will tell you exactly what the problem is. + +Do not proceed with any further steps until direct connections between the +RadSec client and Radsec Server are working properly. + +Once things are working we are ready to +xref:protocols/proxy/radsec_with_haproxy.adoc[configure HAproxy to proxy RadSec +connections] or to xref:protocols/proxy/radsec_with_traefik.adoc[configure +Traefik to proxy RadSec connections]. diff --git a/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_haproxy.adoc b/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_haproxy.adoc new file mode 100644 index 0000000..e58abfe --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_haproxy.adoc @@ -0,0 +1,134 @@ +== Proxying RadSec with HAproxy + +This section shows how to configure HAproxy to proxy RadSec connections. + +The following steps should be performed on the `haproxy` host, unless otherwise +stated. + +Install the HAproxy package supplied with the OS distribution: + +[source,shell] +---- + yum install haproxy +---- + +Stop the haproxy service: + +[source,shell] +---- + service haproxy stop +---- + +Modify the haproxy configuration (typically `/etc/haproxy/haproxy.conf`) so +that it includes new frontend and backend configuration for the radsec service: + +.Example minimal HAproxy configuration +====================================== + + global + maxconn 100 + defaults + mode tcp + timeout connect 10s + timeout client 30s + timeout server 30s + frontend radsec_fe + bind *:2083 + default_backend radsec_be + backend radsec_be + balance roundrobin + server radsecsvr 172.23.0.3:2083 + +====================================== + +Note the `mode tcp` directive which tells HAproxy to act as a Layer 4 +proxy, so that it doesn't attempt to perform SSL termination or +decode the RADIUS protocol. + +[NOTE] +==== +The above example is a minimal configuration. In practise you will want to +retain many of the HAproxy configuration items already present in the +configuration (e.g. `log`, `chroot`, `user`, `group`), but these vary across +distributions. Other HTTP-related options that may already exist in the +configuration will conflict with `mode tcp` (Layer 4 proxying) and should be +removed if HAproxy complains about them. + +However, you should first get things working with the minimal +configuration which is known to work, and then make customisations. +If you start off with a complex configuration, then there may be a +large number of things which are broken, and debugging them all will +be difficult. Start simple, and then add complexity! +==== + +Restart the haproxy service in foreground mode for debugging purposes: + +[source,shell] +---- +haproxy -f /etc/haproxy/haproxy.cfg -db +---- + + +=== Testing RadSec connectivity via HAproxy + +Now edit the test RadSec client, so that instead of making connections directly +to the RadSec server it makes connections to the HAproxy server. + +On `radseccli` edit the `/etc/raddb/sites-enabled/tls` file, and set +the IP address to the address of the `haproxy` host. + +.Example updated test client homeserver configuration +===================================================== + + home_server tls { + ipaddr = 172.23.0.4 # Updated from radsecsvr to haproxy + ... + } + +===================================================== + +Restart the debug mode session: + +[source,shell] +---- +radiusd -X +---- + +Perform a test authentication: + +[source,shell] +---- + echo "User-Name = bob" | radclient 127.0.0.1 auth testing123 +---- + +If the test client is able to successfully establish the RadSec +connection via HAproxy, and the RadSec server replies with an +Access-Accept response, then the output will be as follows: + +.Expected output from radclient +=============================== + + Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27 + Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39 + +=============================== + +HAproxy should also log a message that indicates that the connection was +proxied, such as the following: + +.Expected output from HAproxy +============================= + + <150>...: Connect from 172.23.0.2:50087 to 172.23.0.4:2083 (radius_fr/TCP) + +============================= + +Any other output from radclient or HAproxy indicates that there is a +problem with the HAproxy configuration, or that FreeRADIUS is not +accepting connection from the `haproxy` host, which must be solved +before continuing. + +Once proxied connections are working we are ready to +xref:protocols/proxy/enable_proxy_protocol.adoc[enable the PROXY +Protocol] on both HAproxy and the RadSec server. + diff --git a/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_traefik.adoc b/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_traefik.adoc new file mode 100644 index 0000000..11030e9 --- /dev/null +++ b/doc/antora/modules/howto/pages/protocols/proxy/radsec_with_traefik.adoc @@ -0,0 +1,128 @@ +== Proxying RadSec with Traefik + +This section shows how to configure Traefik to proxy RadSec connections. You +should skip this section if you are not using Traefik as your proxy. + +Installing Traefik is beyond the scope of this guide. It is typically installed +as a service mesh router within a Docker or Kubernetes environment using +offical Docker images. + +Traefik configuration has two components of interest: + + * Static configuration: Defines "entrypoints" on which Traefik listens for connections. + * Dynamic configuration: Defines backend service components and the routing policy. + +Traefik supports a number of providers of dynamic configuration data for the +router and service definitions. For demonstration purposes the files provider +is used here, however you can switch to another provide once you have things +working using this method. + +The static configuration can be provided by starting Traefik with the following +arguments: + +.Example Traefik static configuration +===================================== + + traefik \ + --log.level=DEBUG \ + --providers.file.filename=/etc/traefik/dynamic_config.yml + --providers.file.watch=true + --entryPoints.radsec.address=:2083 + +===================================== + +Note that a `radsec` entrypoint is defined to listen on port 2083 and that a +static `file` provider is used to defined the dynamic services. + +The backend for RadSec should be defined in this file as follows: + +.Example Traefik dynamic configuration +====================================== + + tcp: + routers: + radsec-router: + entryPoints: + - radsec + rule: "HostSNI(`*`)" + service: "radsec-service" + tls: + passthrough: true + services: + radsec-service: + loadBalancer: + servers: + - address: "172.23.0.3:2083" + +====================================== + +Note the `passthrough: true` directive under `tls:` which tells Treafik not to +attempt TLS termination which it would otherwise perform for all incoming TLS +connections. We require that the connection is passed through from the RadSec +client to the RadSec server without being reterminated since the end client's +certificate is authenticated by the RadSec server and many be used for +policy decisions. + + +=== Testing RadSec connectivity via Traefik + +Now amend the test RadSec client so that instead of making connections directly +to the RadSec server it makes them via Traefik. + +On `radseccli` amend `/etc/raddb/sites-enabled/tls` and set the IP address to +that of the `traefik` host. + +.Example updated test client homeserver configuration +===================================================== + + home_server tls { + ipaddr = 172.23.0.5 # Updated from radsecsvr to traefik + ... + } + +===================================================== + +Restart the debug mode session: + +[source,shell] +---- +radiusd -X +---- + +Perform a test authentication: + +[source,shell] +---- + echo "User-Name = bob" | radclient 127.0.0.1 auth testing123 +---- + +If the test client is able to successfully establish the RadSec connection via +Traefik and the RadSec server replies with an Access-Accept response then the +output will be as follows: + +.Example output from radclient +============================== + + Sent Access-Request Id 252 from 0.0.0.0:50118 to 127.0.0.1:1812 length 27 + Received Access-Accept Id 252 from 127.0.0.1:1812 to 127.0.0.1:50118 length 39 + +============================== + +Traefik should also log a message that indicates that the connection was +proxied, such as the following: + +.Example output from Traefik +============================ + + time="..." level=debug msg="Handling connection from 172.23.0.2:57367" + +============================ + +Any other output from radclient or Traefik indicates that there is a problem +with the Traefik configuration or that FreeRADIUS is not accepting connection +from the `traefik` host, which must be solved before continuing. + +Once proxied connections are working we are ready to +xref:protocols/proxy/enable_proxy_protocol.adoc[enable the PROXY Protocol] on +both Traefik and the RadSec server. + |