Table des matières

Configuration de FedeRez Wifi à FedeRez

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.

Configuration des clients

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.

Configuration des proxy

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 

Configuration des sites

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.

Config de l'auth FedeRez

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é).

Configuration des certificats

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
        }
        [...]
}