Cette page concerne la configuration des 2 serveurs centraux de FedeRez, actuellement dodecagon (online) et parangon (lxc Kdell - Cachan Crans)
Il s'agit d'une installation Freeradius3 classique.
Les clients sont les serveurs radius ou nas autorisés à envoyer des requêtes au radius qu'on configure.
Dans le fichier freeradius/3.0/clients.conf, on enregistre les clients des associations + l'autre serveur FedeRez, comme ceci :
##### FEDEREZ WIFI, liste des clients ##### # Liste des clients (serveurs radius) de federez wifi ## CRANS #Ipv4 # Pea (radius 1 du crans) client pea { secret = plop ipaddr = 138.231.148.72 } # eap client eap { secret = plop ipaddr = 138.231.148.71 } ## REZO GIF # Sebulba (radius de test du rezo) client sebulba { secret = plop ipaddr = 160.228.158.188 } # FEDEREZ - Dodecagon client dodecagon { secret = plop ipaddr = 62.210.81.204 } # Local - Monitoring client local { secret = plop ipaddr = 138.231.142.239 } etc...
On met le même secret pour une asso. Il est nécessaire d'enregistrer par ip.
On enregistre ici les serveurs radius distants, donc des assos, auxquels on va forwarder les requêtes.
On choisi par commodité le même secret que ceux dans clients, toujours un par asso.
##### LIST des serveurs radius de federez Wifi : contient au moins IP + SECRET ###### # # # # # Crans START ####################################### realm CRANS { auth_pool = crans_radius_servers nostrip } home_server_pool crans_radius_servers { type = fail-over home_server = eap-Crans home_server = radius-Crans } home_server eap-Crans { type = auth ipaddr = 138.231.148.71 port = 1812 secret = plop require_message_authenticator = yes response_window = 20 zombie_period = 40 revive_interval = 120 status_check = status-server check_interval = 30 num_answers_to_alive = 3 } home_server radius-Crans { type = auth ipaddr = 138.231.148.72 port = 1812 secret = plop require_message_authenticator = yes response_window = 20 zombie_period = 40 revive_interval = 120 status_check = status-server check_interval = 30 num_answers_to_alive = 3 } # Crans STOP ####################################### # Supelec REZO START ################################# realm REZOGif { auth_pool = rezo_radius_servers nostrip } home_server_pool rezo_radius_servers { type = fail-over home_server = organa-rezo home_server = sebulba-rezo } home_server organa-rezo { type = auth ipaddr = 160.228.154.13 port = 1812 secret = plop require_message_authenticator = yes response_window = 20 zombie_period = 40 revive_interval = 120 status_check = status-server check_interval = 30 num_answers_to_alive = 3 } home_server sebulba-rezo { type = auth ipaddr = 160.228.158.188 port = 1812 secret = plop require_message_authenticator = yes response_window = 20 zombie_period = 40 revive_interval = 120 status_check = status-server check_interval = 30 num_answers_to_alive = 3 } # Supelec REZO STOP ################################ etc
Dans sites-enabled, on trouve default et inner-tunnel.
Dans default, on met les réglages qui permettent de forwarder les requêtes en fonction du suffixe. Ex, un login@rezometz.org sera forwarder au radius enregistré dans proxy sous le nom de REZOMETZ.
Pour cela, on modifie légèrement le fichier default, en ajoutant dans autorize ce qui est pasté ci dessous.
La notation unlang est facile à comprendre : si login@plop.org → on active le proxy PLOP.
On note à la fin le cas où le login est @federez.net, dans ce cas on stripp le login comme dans le cas d'un radius d'asso puis on procède à l'auth.
authorize { if ("%{User-Name}" =~ /@(.*)crans(.*)$/) { update control { Proxy-To-Realm := 'CRANS' } } if ("%{User-Name}" =~ /@(.*)rezometz(.*)$/) { update control { Proxy-To-Realm := 'REZOMetz' } } if ("%{User-Name}" =~ /@(.*)iresam(.*)$/) { update control { Proxy-To-Realm := 'IRESAM' } } if ("%{User-Name}" =~ /@(.*)viarezo$/) { update control { Proxy-To-Realm := 'VIAREZO' } } if ("%{User-Name}" =~ /@(.*)larez(.*)$/) { update control { Proxy-To-Realm := 'VIAREZO' } } if ("%{User-Name}" =~ /@(.*)resel(.*)$/) { update control { Proxy-To-Realm := 'RESEL' } } if ("%{User-Name}" =~ /@(.*)rezel(.*)$/) { update control { Proxy-To-Realm := 'REZEL' } } if ("%{User-Name}" =~ /@(.*)minet(.*)$/) { update control { Proxy-To-Realm := 'MINET' } } if ("%{User-Name}" =~ /@(.*)rez-rennes(.*)$/) { update control { Proxy-To-Realm := 'REZORENNES' } } if ("%{request:User-Name}" =~ /^(.*)@federez.net(.*)/){ update request{ Stripped-User-Name := "%{1}" } }
On peut décommenter la ligne qui va bien pour effacer les paramètres post_proxy au passage, en effet, il n'y a pas de raison de transmettre des informations tels que vlan id.
On aurait très bien pu s'arréter ici, mais on souhaite permettre aux users FedeRez de s'auth avec un compte FedeRez. Ces comptes sont stockés dans le ldap.
Par conséquent, on rempli le mods-available/ldap. En particulier, attention à bien faire du tls entre radius et ldap si le serveur ldap ou replica n'est pas sur localhost.
ldap { server = 'localhost' # Administrator account for searching and possibly modifying. # If using SASL + KRB5 these should be commented out. identity = 'cn=federezwifi,ou=service-users,dc=federez,dc=net' password = plop # Unless overridden in another section, the dn from which all # searches will start from. base_dn = 'cn=Utilisateurs,dc=federez,dc=net' sasl { # SASL mechanism # mech = 'PLAIN' # SASL authorisation identity to proxy. # proxy = 'autz_id' # SASL realm. Used for kerberos. # realm = 'example.org' } # WARNING: Although this format is almost identical to the unlang # update section format, it does *NOT* mean that you can use other # unlang constructs in module configuration files. # # Configuration items are in the format: # <radius attr> <op> <ldap attr> # # Request and list qualifiers may also be placed after the 'update' # section name to set defaults destination requests/lists # for unqualified RADIUS attributes. # # Note: LDAP attribute names should be single quoted unless you want # the name value to be derived from an xlat expansion, or an # attribute ref. update { control:Password-With-Header += 'userPassword' control:NT-Password := 'sambaNTPassword' # reply:Reply-Message := 'radiusReplyMessage' # reply:Tunnel-Type := 'radiusTunnelType' # reply:Tunnel-Medium-Type := 'radiusTunnelMediumType' # reply:Tunnel-Private-Group-ID := 'radiusTunnelPrivategroupId' # Where only a list is specified as the RADIUS attribute, # the value of the LDAP attribute is parsed as a valuepair # in the same format as the 'valuepair_attribute' (above). control: += 'radiusControlAttribute' request: += 'radiusRequestAttribute' reply: += 'radiusReplyAttribute' } user { # Where to start searching in the tree for users base_dn = "${..base_dn}" # Filter for user objects, should be specific enough # to identify a single user object. filter = "(&(uid=%{%{Stripped-User-Name}:-%{User-Name}})(objectClass=sambaSamAccount))" # SASL parameters to use for user binds sasl { } # Search scope, may be 'base', 'one', sub' or 'children' # scope = 'sub' # Server side result sorting # sort_by = '-uid' # If this is undefined, anyone is authorised. # If it is defined, the contents of this attribute # determine whether or not the user is authorised # access_attribute = 'dialupAccess' # access_positive = yes } # # User membership checking. # group { # Where to start searching in the tree for groups base_dn = "${..base_dn}" # Filter for group objects, should match all available # group objects a user might be a member of. filter = '(objectClass=posixGroup)' # Search scope, may be 'base', 'one', sub' or 'children' # scope = 'sub' # Attribute that uniquely identifies a group. # Is used when converting group DNs to group # names. # name_attribute = cn # Filter to find group objects a user is a member of. # That is, group objects with attributes that # identify members (the inverse of membership_attribute). # membership_filter = "(|(member=%{control:Ldap-UserDn})(memberUid=%{%{Stripped-User-Name}:-%{User-Name}}))" # The attribute in user objects which contain the names # or DNs of groups a user is a member of. # # Unless a conversion between group name and group DN is # needed, there's no requirement for the group objects # referenced to actually exist. membership_attribute = 'memberOf' # Override the normal cache attribute (<inst>-LDAP-Group or # LDAP-Group if using the default instance) and create a # custom attribute. This can help if multiple module instances # are used in fail-over. # cache_attribute = 'LDAP-Cached-Membership' } profile { } client { # Where to start searching in the tree for clients base_dn = "${..base_dn}" # # Filter to match client objects # filter = '(objectClass=radiusClient)' # # Sets default values (not obtained from LDAP) for new client entries # template { } attribute { ipaddr = 'radiusClientIdentifier' secret = 'radiusClientSecret' } } # Load clients on startup # read_clients = no accounting { reference = "%{tolower:type.%{Acct-Status-Type}}" type { start { update { description := "Online at %S" } } interim-update { update { description := "Last seen at %S" } } stop { update { description := "Offline at %S" } } } } # # Post-Auth can modify LDAP objects too # post-auth { update { description := "Authenticated at %S" } } # # LDAP connection-specific options. # # These options set timeouts, keep-alives, etc. for the connections. # options { # Control under which situations aliases are followed. # May be one of 'never', 'searching', 'finding' or 'always' # default: libldap's default which is usually 'never'. # # LDAP_OPT_DEREF is set to this value. # dereference = 'always' # # The following two configuration items control whether the # server follows references returned by LDAP directory. # They are mostly for Active Directory compatibility. # If you set these to 'no', then searches will likely return # 'operations error', instead of a useful result. # chase_referrals = yes rebind = yes # Seconds to wait for LDAP query to finish. default: 20 res_timeout = 10 # Seconds LDAP server has to process the query (server-side # time limit). default: 20 # # LDAP_OPT_TIMELIMIT is set to this value. srv_timelimit = 3 # Seconds to wait for response of the server. (network # failures) default: 10 # # LDAP_OPT_NETWORK_TIMEOUT is set to this value. net_timeout = 1 # LDAP_OPT_X_KEEPALIVE_IDLE idle = 60 # LDAP_OPT_X_KEEPALIVE_PROBES probes = 3 # LDAP_OPT_X_KEEPALIVE_INTERVAL interval = 3 # ldap_debug: debug flag for LDAP SDK # (see OpenLDAP documentation). Set this to enable # huge amounts of LDAP debugging on the screen. # You should only use this if you are an LDAP expert. # # default: 0x0000 (no debugging messages) # Example:(LDAP_DEBUG_FILTER+LDAP_DEBUG_CONNS) ldap_debug = 0x0028 } tls { # start_tls = yes # ca_file = ${certdir}/cacert.pem # ca_path = ${certdir} # certificate_file = /path/to/radius.crt # private_key_file = /path/to/radius.key # random_file = /dev/urandom # require_cert = 'demand' } # As of version 3.0, the 'pool' section has replaced the # following configuration items: # # When the server is not threaded, the connection pool # limits are ignored, and only one connection is used. pool { # Connections to create during module instantiation. # If the server cannot create specified number of # connections during instantiation it will exit. # Set to 0 to allow the server to start without the # directory being available. start = ${thread[pool].start_servers} # Minimum number of connections to keep open min = ${thread[pool].min_spare_servers} max = ${thread[pool].max_servers} # Spare connections to be left idle # # NOTE: Idle connections WILL be closed if "idle_timeout" # is set. This should be less than or equal to "max" above. spare = ${thread[pool].max_spare_servers} # Number of uses before the connection is closed # # 0 means "infinite" uses = 0 # The number of seconds to wait after the server tries # to open a connection, and fails. During this time, # no new connections will be opened. retry_delay = 30 # The lifetime (in seconds) of the connection lifetime = 0 # Idle timeout (in seconds). A connection which is # unused for this length of time will be closed. idle_timeout = 60 } }
On active ensuite le module ldap en faisant un lien symbolique dans mods-enabled. On vérifie que dans les sites il est bien fait référence à ldap (non commenté).
Afin d'éviter d'utiliser des certificats auto-signés, on peut utiliser ceux générés par Let's Encrypt. Pour celà, on commence par créer des liens symboliques dans le dossier certs :
cd /etc/freeradius/3.0/certs ln -s /etc/letsencrypt/live/dodecagon.federez.net/cert.pem cert.pem ln -s /etc/letsencrypt/live/dodecagon.federez.net/fullchain.pem fullchain.pem ln -s /etc/letsencrypt/live/dodecagon.federez.net/privkey.pem server.key
On peut ensuite modifier la configuration de eap pour en tenir compte :
eap { [...] tls-config tls-LEcert { private_key_file = ${certdir}/server.key certificate_file = ${certdir}/cert.pem ca_file = ${certdir}/fullchain.pem dh_file = ${certdir}/dh ca_path = ${cadir} cipher_list = "DEFAULT" cipher_server_preference = no tls_min_version = "1.0" tls_max_version = "1.2" ecdh_curve = "prime256v1" cache { enable = yes lifetime = 1 # hours } verify { } ocsp { enable = no override_cert_url = yes url = "http://127.0.0.1/ocsp/" } } [...] ttls { tls = tls-LEcert } [...] peap { tls = tls-LEcert } [...] }