diff --git a/README.md b/README.md index 14c4a2e44964e57145ffe117ae5589d5cd4ab3e5..17060444cea3021ea21a4129bc9e5c8ebb21315c 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,13 @@ * [`freeradius::client`](#freeradiusclient) * [`freeradius::config`](#freeradiusconfig) * [`freeradius::dictionary`](#freeradiusdictionary) + * [`freeradius::home_server`](#freeradiushomeserver) + * [`freeradius::home_server_pool`](#freeradiushomeserverpool) * [`freeradius::instantiate`](#freeradiusinstantiate) * [`freeradius::ldap`](#freeradiusldap) * [`freeradius::module`](#freeradiusmodule) * [`freeradius::policy`](#freeradiuspolicy) + * [`freeradius::realm`](#freeradiusrealm) * [`freeradius::site`](#freeradiussite) * [`freeradius::sql`](#freeradiussql) * [`freeradius::statusclient`](#freeradiusstatusclient) @@ -259,6 +262,84 @@ freeradius::dictionary { 'mydict': source => 'puppet:///modules/site_freeradius/dictionary.mydict', } ``` +#### `freeradius::home_server` + +This section defines a "Home Server" which is another RADIUS server that gets sent proxied requests. + +##### `secret` + +The shared secret use to "encrypt" and "sign" packets between FreeRADIUS and the home server. + +##### `type` + +Home servers can be sent Access-Request packets or Accounting-Request packets. Allowed values are: +* `auth` Handles Access-Request packets +* `acct` Handles Accounting-Request packets +* `auth+acct` Handles Access-Request packets at "port" and Accounting-Request packets at "port + 1" +* `coa` Handles CoA-Request and Disconnect-Request packets. + +Default: `auth` + +##### `ipaddr` + +IPv4 address or hostname of the home server. Specify one of `ipaddr`, `ipv6addr` or `virtual_server` + +##### `ipv6addr` + +IPv6 address or hostname of the home server. Specify one of `ipaddr`, `ipv6addr` or `virtual_server` + +##### `virtual_server` + +If you specify a virtual_server here, then requests will be proxied internally to that virtual server. +These requests CANNOT be proxied again, however. The intent is to have the local server handle packets +when all home servers are dead. Specify one of `ipaddr`, `ipv6addr` or `virtual_server` + +##### `port` + +The port to which packets are sent. Usually 1812 for type "auth", and 1813 for type "acct". +Older servers may use 1645 and 1646. Use 3799 for type "coa" Default: `1812` + +##### `proto` +The transport protocol. If unspecified, defaults to "udp", which is the traditional +RADIUS transport. It may also be "tcp", in which case TCP will be used to talk to +this home server. Default: `udp` + + +#### `freeradius::home_server_pool` + +##### `home_server` + +An array of one or more home servers. The names of the home servers are NOT the hostnames, but the names +of the sections. (e.g. `home_server foo {...}` has name "foo". + +Note that ALL home servers listed here have to be of the same type. i.e. they all have to be "auth", or they all have to +be "acct", or they all have to be "auth+acct". + + +##### `type` + +The type of this pool controls how home servers are chosen. + +* `fail-over` the request is sent to the first live home server in the list. i.e. If the first home server is marked "dead", the second one is chosen, etc. +* `load-balance` the least busy home server is chosen For non-EAP auth methods, and for acct packets, we recommend using "load-balance". It will ensure the highest availability for your network. +* `client-balance` the home server is chosen by hashing the source IP address of the packet. This configuration is most useful to do simple load balancing for EAP sessions +* `client-port-balance` the home server is chosen by hashing the source IP address and source port of the packet. +* `keyed-balance` the home server is chosen by hashing (FNV) the contents of the Load-Balance-Key attribute from the control items. + +The default type is `fail-over`. + +##### `virtual_server` + +A `virtual_server` may be specified here. If so, the "pre-proxy" and "post-proxy" sections are called when +the request is proxied, and when a response is received. + +##### `fallback` + +If ALL home servers are dead, then this "fallback" home server is used. If set, it takes precedence over any realm-based +fallback, such as the DEFAULT realm. + +For reasons of stability, this home server SHOULD be a virtual server. Otherwise, the fallback may itself be dead! + #### `freeradius::instantiate` @@ -381,6 +462,37 @@ freeradius::policy { 'my-policies': } ``` +#### `freeradius::realm` + +Define a realm in `proxy.conf`. Realms point to pools of home servers. + +##### `virtual_server` + +Set this to "proxy" requests internally to a virtual server. The pre-proxy and post-proxy sections are run just as with any +other kind of home server. The virtual server then receives the request, and replies, just as with any other packet. +Once proxied internally like this, the request CANNOT be proxied internally or externally. + +##### `auth_pool` + +For authentication, the `auth_pool` configuration item should point to a `home_server_pool` that was previously +defined. All of the home servers in the `auth_pool` must be of type `auth`. + +##### `acct_pool` + +For accounting, the `acct_pool` configuration item should point to a `home_server_pool` that was previously +defined. All of the home servers in the `acct_pool` must be of type `acct`. + +##### `pool` + +If you have a `home_server_pool` where all of the home servers are of type `auth+acct`, you can just use the `pool` +configuration item, instead of specifying both `auth_pool` and `acct_pool`. + +##### `nostrip` + +Normally, when an incoming User-Name is matched against the realm, the realm name is "stripped" off, and the "stripped" +user name is used to perform matches.If you do not want this to happen, set this to `true`. Default: `false`. + + #### `freeradius::script` Install a helper script, e.g. which might be called upon by a virtual server. These are diff --git a/manifests/home_server.pp b/manifests/home_server.pp new file mode 100644 index 0000000000000000000000000000000000000000..8152cd342a8fca7edf9b342c7e4fd8673e8629aa --- /dev/null +++ b/manifests/home_server.pp @@ -0,0 +1,33 @@ +# Configure a home_server for proxy config +define freeradius::home_server ( + $secret, + $type = 'auth', + $ipaddr = '', + $ipv6addr = '', + $virtual_server = '', + $port = 1812, + $proto = 'udp', +) { + $fr_basepath = $::freeradius::params::fr_basepath + + # Validate multiple choice options + unless $type in ['auth', 'acct', 'auth+acct', 'coa'] { + fail('$type must be one of auth, acct, auth+acct, coa') + } + unless $proto in ['udp', 'tcp'] { + fail('$type must be one of udp, tcp') + } + + # Validate integers + unless is_integer($port) { + fail('$port must be an integer') + } + + # Configure config fragment for this home server + concat::fragment { "homeserver-${name}": + target => "${fr_basepath}/proxy.conf", + content => template('freeradius/home_server.erb'), + order => 10, + } +} + diff --git a/manifests/home_server_pool.pp b/manifests/home_server_pool.pp new file mode 100644 index 0000000000000000000000000000000000000000..e680ec014eb6442c6cb93c86458765cf6c21a427 --- /dev/null +++ b/manifests/home_server_pool.pp @@ -0,0 +1,22 @@ +# Configure home server pools +define freeradius::home_server_pool ( + $home_server, + $type = 'fail-over', + $virtual_server = '', + $fallback = '', +) { + $fr_basepath = $::freeradius::params::fr_basepath + + # Validate multi-value options + unless $type in ['fail-over', 'load-balance', 'client-balance', 'client-port-balance', 'keyed-balance'] { + fail('$type must be one of fail-over, load-balance, client-balance, client-port-balance, keyed-balance') + } + + # Configure config fragment for this home server + concat::fragment { "homeserverpool-${name}": + target => "${fr_basepath}/proxy.conf", + content => template('freeradius/home_server_pool.erb'), + order => 20, + } +} + diff --git a/manifests/init.pp b/manifests/init.pp index a8607762e7c02c511a2d4f3aa92e6c4f28fc01b1..71fe7590256dc78604f378163186a52950f1e444 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -71,6 +71,7 @@ class freeradius ( group => $freeradius::fr_group, mode => '0640', require => [Package[$freeradius::fr_package], Group[$freeradius::fr_group]], + notify => Service[$freeradius::fr_service], } concat::fragment { 'policy_header': target => "${freeradius::fr_basepath}/policy.conf", @@ -83,6 +84,15 @@ class freeradius ( order => '99', } + # Set up concat proxy file + concat { "${freeradius::fr_basepath}/proxy.conf": + owner => 'root', + group => $freeradius::fr_group, + mode => '0640', + require => [Package[$freeradius::fr_package], Group[$freeradius::fr_group]], + notify => Service[$freeradius::fr_service], + } + # Install a slightly tweaked stock dictionary that includes # our custom dictionaries concat { "${freeradius::fr_basepath}/dictionary": @@ -264,7 +274,6 @@ class freeradius ( file { [ "${freeradius::fr_basepath}/sites-available/default", "${freeradius::fr_basepath}/sites-available/inner-tunnel", - "${freeradius::fr_basepath}/proxy.conf", "${freeradius::fr_basepath}/clients.conf", "${freeradius::fr_basepath}/sql.conf", ]: diff --git a/manifests/realm.pp b/manifests/realm.pp new file mode 100644 index 0000000000000000000000000000000000000000..ec67cb49df1c3076ae987dadef2aa556b2d3b121 --- /dev/null +++ b/manifests/realm.pp @@ -0,0 +1,22 @@ +# Set up proxy realms +define freeradius::realm ( + $virtual_server = '', + $auth_pool = '', + $acct_pool = '', + $pool = '', + $nostrip = false, +) { + $fr_basepath = $::freeradius::params::fr_basepath + + # Validate bools + unless is_bool($nostrip) { + fail('nostrip must be true or false') + } + + # Configure config fragment for this realm + concat::fragment { "realm-${name}": + target => "${fr_basepath}/proxy.conf", + content => template('freeradius/realm.erb'), + order => 30, + } +} diff --git a/templates/home_server.erb b/templates/home_server.erb new file mode 100644 index 0000000000000000000000000000000000000000..bd207df05334dc1486bce1e5622244ced3588f54 --- /dev/null +++ b/templates/home_server.erb @@ -0,0 +1,16 @@ +home_server <%= @name %> { + type = <%= @type %> +<% if @ipaddr != '' -%> + ipaddr = <%= @ipaddr %> +<% end -%> +<% if @ipv6addr != '' -%> + ipv6addr = <%= @ipv6addr %> +<% end -%> +<% if @virtual_server != '' -%> + virtual_server = <%= @virtual_server %> +<% end -%> + port = <%= @port %> + proto = <%= @proto %> + secret = <%= @secret %> +} + diff --git a/templates/home_server_pool.erb b/templates/home_server_pool.erb new file mode 100644 index 0000000000000000000000000000000000000000..e33132a7ab9fb0e061183019feb679684baca552 --- /dev/null +++ b/templates/home_server_pool.erb @@ -0,0 +1,13 @@ +home_server_pool <%= @name %> { + type = <%= @type %> +<% if @virtual_server != '' -%> + virtual_server = <%= @virtual_server %> +<% end -%> +<% @home_server.each do |server| -%> + home_server = <%= server %> +<% end -%> +<% if @fallback != '' -%> + fallback = <%= @fallback %> +<% end -%> +} + diff --git a/templates/realm.erb b/templates/realm.erb new file mode 100644 index 0000000000000000000000000000000000000000..59ae0203b7875fd467bdd2c66c83e1790e4ceb27 --- /dev/null +++ b/templates/realm.erb @@ -0,0 +1,18 @@ +realm <%= @name %> { +<% if @virtual_server != '' -%> + virtual_server = <%= @virtual_server %> +<% end -%> +<% if @auth_pool != '' -%> + auth_pool = <%= @auth_pool %> +<% end -%> +<% if @acct_pool != '' -%> + acct_pool = <%= @acct_pool %> +<% end -%> +<% if @pool != '' -%> + pool = <%= @pool %> +<% end %> +<% if @nostrip -%> + nostrip +<% end -%> +} +