Un brin de réseau


Tel un cahier de notes, ce blog propose des articles sur les technologies réseaux et leur utilisation pratique, le tout illustré avec des maquettes et des captures.

#about #contact

(Free)RADIUS

Un peu d'anatomie : le radius, c'est un os de l'avant-bras. Mais le RADIUS (Remote Authentication Dial In User Service), c'est un protocole ou service à mi-chemin entre les mondes réseau et système. En effet, dans le contexte opérateur par exemple, les clients RADIUS sont souvent des équipements réseaux (routeurs) et les serveurs RADIUS des machines Linux ou Windows (virtuelles ou physiques). En ceci, c'est une technologie souvent non maîtrisée—ou qui apparaît mystique—car l'équipe réseau considère que c'est à l'équipe système de s'en charger et vice-versa ! Par ailleurs, au-delà de l'aspect purement protocolaire, il y a, en particulier dans l'implémentation FreeRADIUS, un fort aspect algorithmique qui rejoint le monde du dév. Cela rend l'outil très puissant—car de nombreux traitements à valeur ajoutée peuvent être exécutés—et, me concernant, j'ai beaucoup apprécié travailler avec et me perdre dans les détails techniques. En conclusion, le RADIUS est pluridisciplinaire et reflète bien la diversité inhérente à nos métiers d'ingénieurs réseaux-systèmes.

Le RADIUS, ça Suze

Admettons-le, la définition de la RFC 2865 ne cache pas l'âge avancé du RADIUS (années 1990, c'est pas si vieux en fait…) :


  Managing dispersed serial line and modem pools for large numbers of
  users can create the need for significant administrative support.
  Since modem pools are by definition a link to the outside world, they
  require careful attention to security, authorization and accounting.
  This can be best achieved by managing a single "database" of users,
  which allows for authentication (verifying user name and password) as
  well as configuration information detailing the type of service to
  deliver to the user (for example, SLIP, PPP, telnet, rlogin).
  

En effet, ci-dessus apparaîssent les termes vieillissant de lignes série, modem et PPP. Mais soyez assurés, le RADIUS est une technologie bien actuelle, en lien avec la sécurité, qui fonctionne de pair avec par exemple : DHCP, LDAP, 802.1x, etc. Nous pouvons retenir que le RADIUS permet deux choses :

La database peut correspondre à un simple fichier texte formatté d'une certaine façon (exemple) ou, plus idéalement, à une base SQL (facilitant ainsi l'exploitation des données).

Aux AA(A?)

Attention au terme « autorisés » utilisé plus haut, volontairement par abus de langage, qui rejoint la notion d'AAA (Authentication, Authorization and Accounting). Le concept est bien expliqué dans la documentation NetworkRADIUS :

On dit aussi que le RADIUS est un protocole AAA, à l'instar des protocoles DIAMETER et TACACS.

Vous n'avez pas les bases

Point de vue protocolaire, le RADIUS se suffit généralement de cinq types de message :


  1       Access-Request
  2       Access-Accept
  3       Access-Reject
  4       Accounting-Request
  5       Accounting-Response
  

La séquence est plutôt intuitive et suit le modèle classique client-serveur :

radius-sequence
Le parallèle avec la notion d'AAA a été fait dans le schéma. Noter qu'il y a trois types d'accounting : début de session (Start), milieu pour du keepalive (Interim-Update) et fin (Stop).

Chacun ses attributs

Chaque message contient—ou non, selon son type—les fameux attributs RADIUS. Il s'agit d'informations (sous la forme clé-valeur) requises ou utiles à l'établissement et au maintien de la session. Des extraits, issus d'une capture Wireshark, seront plus parlants :


  Code: Access-Request (1)
  Attribute Value Pairs
      AVP: t=User-Name(1) val=my-super-box@the-operator
      AVP: t=CHAP-Password(3) val=c64cb06d8c466dcd8434b4c31b60b05169
      AVP: t=NAS-Identifier(32) val=my-super-nas
      AVP: t=Calling-Station-Id(31) val=aa:bb:cc:dd:ee:ff
  

Le message Access-Request est envoyé du NAS au serveur RADIUS afin d'authentifier—et d'autoriser comme nous le verrons ci-après—l'utilisateur. Il contient principalement le couple username-password mais beaucoup d'autres informations peuvent y être comme le nom du NAS ou encore l'adresse MAC de la box. Le serveur RADIUS s'en servira si besoin pour effectuer divers traitements algorithmiques.


  Code: Access-Accept (2)
  Attribute Value Pairs
      AVP: t=Framed-IP-Address(8) val=1.2.3.4
      AVP: t=Framed-IP-Netmask(9) val=255.255.255.255
      AVP: t=Vendor-Specific(26) vnd=ciscoSystems(9)
          VSA: t=Cisco-AVPair(1) val=qos-policy-out=add-class(sub,(class-default),shape(100000000)
  

Le message Access-Accept a un double rôle—comme illustré sur le schéma. D'une part, il valide l'authentification (auth) de l'utilisateur auprès du NAS et d'autre part, il retourne les autorisations (autz) via les attributs contenus dans le message. Bien comprendre que autorisations ne signifient pas forcément niveau de droits ou liste de commandes tolérées—d'ailleurs, je ne l'ai vu que rarement. Dans l'exemple ci-dessus, il y a l'adresse IP publique que le NAS assignera à la box et le débit descendant souscrit par le client associé. Il s'agit bien d'autorisations : ainsi, le client en question sera autorisé à accéder à Internet grâce à son IP et avec un débit de 100 Mbps en download. Pour un autre client, ce débit pourra être inférieur ou supérieur selon les options souscrites.


  Code: Accounting-Request (4)
  Attribute Value Pairs
      AVP: t=Acct-Status-Type(40) val=Start(1)
      AVP: t=Acct-Session-Id(44) val=000000bf
      AVP: t=User-Name(1) val=my-super-box@the-operator
      AVP: t=NAS-Identifier(32) val=my-super-nas
      AVP: t=Calling-Station-Id(31) val=aa:bb:cc:dd:ee:ff
  

Une fois les étapes auth et autz réalisées, l'étape optionnelle acct peut alors débuter avec un message Accounting-Request de type Start envoyé du NAS au serveur RADIUS. L'intérêt de cette étape d'accounting est le suivi de l'utilisateur (est-il en ligne ? hors ligne ? quelle consommation de données ?). On imagine tout à fait une interface Web indiquant en vert les utilisateurs en ligne et en rouge ceux hors ligne, par exemple. Ici aussi, en plus d'un ID de session, beaucoup d'autres informations utiles ou non au serveur RADIUS peuvent être contenues dans le message.


  Code: Accounting-Response (5)
  Packet identifier: 0x32 (50)
  

Le message Accounting-Response, en réponse aux trois types d'accounting, ne contient pas d'attributs (RFC 2866 § 4.2). C'est juste un ack. Il contient cependant un identifiant de paquet, comme tout message RADIUS en fait, et ce, à des fins de séquencement et de retransmission (mais ce n'est pas vraiment intéressant de le remarquer ici).


  Code: Accounting-Request (4)
  Attribute Value Pairs
      AVP: t=Acct-Status-Type(40) val=Interim-Update(3)
      AVP: t=Acct-Session-Id(44) val=000000bf
      AVP: t=User-Name(1) val=my-super-box@the-operator
      AVP: t=Acct-Input-Octets(42) val=2035
      AVP: t=Acct-Output-Octets(43) val=1246
      AVP: t=NAS-Identifier(32) val=my-super-nas
      AVP: t=Calling-Station-Id(31) val=aa:bb:cc:dd:ee:ff
  

Le message Accounting-Request de type Interim-Update est tel un keepalive. Il indique périodiquement que l'utilisateur est toujours en ligne (à l'instar d'un ping) mais surtout il précise la consommation de ce dernier (attributs Acct-Input-Octets et Acct-Output-Octets).


  Code: Accounting-Request (4)
  Attribute Value Pairs
      AVP: t=Acct-Status-Type(40) val=Stop(2)
      AVP: t=Acct-Session-Id(44) val=000000bf
      AVP: t=User-Name(1) val=my-super-box@the-operator
      AVP: t=Acct-Input-Octets(42) val=2521
      AVP: t=Acct-Output-Octets(43) val=1674
      AVP: t=Acct-Terminate-Cause(49) val=Admin-Reset(6)
      AVP: t=NAS-Identifier(32) val=my-super-nas
      AVP: t=Calling-Station-Id(31) val=aa:bb:cc:dd:ee:ff
  

Enfin, le message Accounting-Request de type Stop indique que l'utilisateur est passé hors ligne. Plusieurs causes sont possibles (RFC 2866) : coupure volontaire (comme c'est le cas ici) ou involontaire, etc.

Du contexte

Sauf tests particuliers, la séquence RADIUS présentée plus haut rentre toujours dans un contexte d'accès des utilisateurs au réseau. C'est souvent soit en DHCP soit en PPP(oE). Ci-dessous des schémas intégrant cette séquence à ces deux cas.

Du FreeRADIUS

FreeRADIUS est un projet open source (GitHub) proposant une implémentation d'un serveur RADIUS sous Linux. Nous rentrons donc un peu plus dans le monde système.


    Welcome to the FreeRADIUS project, the open source implementation of RADIUS,
    an IETF protocol for AAA (Authorisation, Authentication, and Accounting).

    The FreeRADIUS project maintains the following components:
    a multi protocol policy server (radiusd) that implements RADIUS, DHCP, BFD, and ARP; (…)
  

En réalité, aujourd'hui FreeRADIUS va plus loin et embarque notamment un serveur DHCP.

Soyons technique.

Le but ici n'est pas de décrire bêtement l'installation d'un serveur FreeRADIUS et sa configuration initiale. Tout le monde sait lire un tutoriel, et ce n'est pas ce qui manque sur la toile. Le but est de survoler la séquence RADIUS, comprendre sa logique et son algorithmie en lien avec la notion d'AAA introduite plus haut. Pour ce faire, un extrait de la séquence par défaut constitue une bonne base :


    server default {
      #
      # L3-L4 configuration for auth (and autz).
      #
      listen {
        type = auth
        ipaddr = *
        port = 1812
        (…)
      }
      #
      # L3-L4 configuration for acct.
      #
      listen {
        type = acct
        ipaddr = *
        port = 1813
        (…)
      }
    

Ci-dessus, rien de bien compliqué. Ces lignes indiquent sur quelles IP et quels ports UDP le serveur RADIUS écoute pour l'auth (autz inclus) et l'acct. De nombreux autres paramètres—non pertinents nous concernant—peuvent être configurés. Le mieux reste alors de consulter le fichier suscité qui est généreusement commenté.

On s'ennuit là.

Bon ok. Rentrons dans le vif du sujet. À la réception d'un Access-Request, les trois sections suivantes sont exécutées, l'une après l'autre :


      #
      # Handle an Access-Request packet.
      #
      authorize {
        filter_username
        preprocess
        chap
        suffix
        sql
        (…)
        pap
        (…)
      }
      authenticate {
        Auth-Type PAP {
          pap
        }
        Auth-Type CHAP {
          chap
        }
      }
      post-auth {
        sql
        (…)
        Post-Auth-Type REJECT {
          sql
          attr_filter.access_reject
        }
      }
    

La section authorize contient en fait le plus d'intelligence. Les noms des modules appelés sont assez parlants je trouve. Ainsi, elle va, notamment, s'assurer que le format du username est correct (pas d'espace, etc.), effectuer des traitements préliminaires si besoin (ajout d'attributs dans la requête, etc.), indiquer le type d'authentification (PAP ou CHAP, typiquement) et récupérer les attributs RADIUS en base (en l'occurrence—cela pourrait aussi être dans un fichier texte).

De plus, via le module suffix, elle va interpréter la notion de realm. On peut traduire ceci par royaume ou plutôt domaine. En général (mais pas toujours), les noms d'utilisateur suivent en effet le format User-Name@Realm (par exemple, cpe@operator1.fr). Pourquoi ceci ? Une fois encore, cela permet d'effectuer des traitements spécifiques selon le realm reçu, et en particulier du proxy RADIUS (RFC 2865 § 2.3). Le cas d'école est lorsqu'un opérateur en rachète un autre. Idéalement, il faudrait unifier les serveurs RADIUS des différentes structures. Cependant, cela demande un travail non négligeable, sachant que FreeRADIUS n'est pas le seul produit sur le marché. Aussi, entre temps, le proxy peut sauver la mise, en permettant aux différents serveurs de se requêter entre eux.


      #
      # Handle an Accounting-Request packet.
      #
      preacct {
        preprocess
        acct_unique
        suffix
      }
      accounting {
        detail
        sql
        (…)
        attr_filter.accounting_response
      }
      session {
      }
    

      #
      # If proxying is needed (the "suffix" module tells if it is the case).
      # This applies for both Access-Request and Accounting-Request packets.
      #
      pre-proxy { }
      post-proxy { }
    }
  

Suite en cours de rédaction.