НейроАгент

Руководство по логированию внутреннего имени пользователя в FreeRADIUS EAP-TTLS/PAP

Узнайте, как настроить FreeRADIUS с использованием linelog для захвата и логирования внутреннего имени пользователя из запросов аутентификации EAP-TTLS/PAP вместо логирования только внешней анонимной идентичности. Полное руководство с примерами конфигурации.

Вопрос

Как настроить FreeRADIUS с модулем linelog для захвата и логирования внутреннего имени пользователя из запросов аутентификации EAP-TTLS/PAP вместо логирования только внешнего анонимного идентификатора?

Я настраиваю FreeRADIUS для проксирования запросов EAP-TTLS/PAP на RADIUS-сервер, который поддерживает только обычную аутентификацию PAP. Хотя проксирование и логирование работают корректно, текущая конфигурация linelog логирует только User-Name из внешнего туннельного запроса (который по умолчанию является ‘anonymous’ для клиентов Android). Мне нужно получить и залогировать фактическое имя пользователя, предоставленное внутри внутреннего туннеля для целей аутентификации.

Текущие файлы конфигурации:

sites-enabled/default:

server default {
    listen {
        type = auth
        ipaddr = *
        port = 1812

        limit {
            max_connections = 16
            lifetime = 0
            idle_timeout = 30
        }
    }

    listen {
        type = acct
        ipaddr = *
        port = 1813

        limit {
            max_connections = 16
            lifetime = 0
            idle_timeout = 30
        }
    }

    listen {
        type = auth
        ipv6addr = ::
        port = 1812

        limit {
            max_connections = 16
            lifetime = 0
            idle_timeout = 30
        }
    }

    listen {
        type = acct
        ipv6addr = ::
        port = 1813

        limit {
            max_connections = 16
            lifetime = 0
            idle_timeout = 30
        }
    }

    authorize {
        eap {
            ok = return
        }

        pap

        update control {
            &Proxy-To-Realm := "authentik"
        }
    }

    authenticate {
        Auth-Type PAP {
            pap
        }

        eap
    }

    post-auth {
        log_access
        
        update {
            &reply: += &session-state:
        }

        if (&reply:EAP-Session-Id) {
            update reply {
                EAP-Key-Name := &reply:EAP-Session-Id
            }
        }
    }

    post-proxy {
        eap
    }

    accounting {
        log_accounting
    }
}

mods-enabled/eap:

eap {
    default_eap_type = ttls
    timer_expire = 60
    ignore_unknown_eap_types = no
    max_sessions = ${max_requests}

    tls-config tls-common {
        private_key_file = /certs/live/{DOMAIN}/privkey.pem
        certificate_file = /certs/live/{DOMAIN}/fullchain.pem

        cipher_list = "DEFAULT"
        cipher_server_preference = no

        tls_min_version = "1.2"
        tls_max_version = "1.3"

        ecdh_curve = ""

        cache {
            enable = no
            lifetime = 24

            store {
                Tunnel-Private-Group-Id
            }
        }

        ocsp {
            enable = no
            override_cert_url = yes
            url = "http://127.0.0.1/ocsp/"
        }
    }

    ttls {
        tls = tls-common
        default_eap_type = pap

        copy_request_to_tunnel = no
        use_tunneled_reply = no

        virtual_server = "default"
    }
}

mods-enabled/linelog:

linelog log_access {
    filename = ${logdir}/custom/log_access.log
    permissions = 0600

    reference = "messages.%{%{reply:Packet-Type}:-default}"

    messages {
        default = "timestamp=\"%t\" event=\"ACCESS-OTHER\" packet_type=\"%{Packet-Type}\" user=\"%{User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
        
        Access-Accept = "timestamp=\"%t\" event=\"ACCESS-ACCEPT\" user=\"%{User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
        Access-Reject = "timestamp=\"%t\" event=\"ACCESS-REJECT\" user=\"%{User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" reason=\"%{Module-Failure-Message}\""
    }
}

linelog log_accounting {
    filename = ${logdir}/custom/log_accounting.log
    permissions = 0600

    reference = "messages.%{%{Acct-Status-Type}:-default}"

    messages {
        default = "timestamp=\"%t\" event=\"ACCT-OTHER\" acct_status=\"%{Acct-Status-Type}\" user=\"%{User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" session_id=\"%{Acct-Session-Id}\""

        Start = "timestamp=\"%t\" event=\"ACCT-START\" user=\"%{User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" session_id=\"%{Acct-Session-Id}\""
        Stop = "timestamp=\"%t\" event=\"ACCT-STOP\" user=\"%{User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" session_id=\"%{Acct-Session-Id}\" duration_sec=\"%{Acct-Session-Time}\""
        
        Accounting-On = "timestamp=\"%t\" event=\"ACCT-ON\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
        Accounting-Off = "timestamp=\"%t\" event=\"ACCT-OFF\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
    }
}

Текущие журналы:
log_access.log:

timestamp="Wed Nov  5 17:30:31 2025" event="ACCESS-ACCEPT" user="someuser" client_mac="" nas_id="" nas_ip=""
timestamp="Wed Nov  5 17:30:29 2025" event="ACCESS-ACCEPT" user="anonymous" client_mac="someid" nas_id="someid" nas_ip="10.0.5.x"

log_accounting.log:

timestamp="Wed Nov  5 17:29:15 2025" event="ACCT-STOP" user="anonymous" client_mac="someid" nas_id="someid" nas_ip="10.0.5.x" session_id="4DCA6606E70B1D31" duration_sec="3333"
timestamp="Wed Nov  5 17:30:34 2025" event="ACCT-START" user="anonymous" client_mac="someid" nas_id="someid" nas_ip="10.0.5.x" session_id="02A4FDCAB6135746"

Какие конкретные изменения мне нужно внести в мою конфигурацию FreeRADIUS, чтобы захватывать и логировать внутреннее имя пользователя в журналах доступа и учета?

НейроАгент

Для захвата и регистрации внутреннего имени пользователя из запросов аутентификации EAP-TTLS/PAP необходимо изменить конфигурацию FreeRADIUS, чтобы сохранить внутреннее имя пользователя в процессе аутентификации и правильно сослаться на него в конфигурации linelog.

Основная проблема заключается в том, что текущая конфигурация ссылается только на внешний атрибут User-Name, который для клиентов Android отображается как “anonymous”. Вам необходимо получить доступ к фактическому имени пользователя, предоставленному во внутреннем туннеле.

Содержание

Понимание потока внутреннего/внешнего имени пользователя

В аутентификации EAP-TTLS существуют два различных потока имени пользователя:

  1. Внешнее имя пользователя: Это идентификатор, отправляемый в открытом виде во время начального рукопожатия. Клиенты Android часто отправляют “anonymous” для обеспечения конфиденциальности.

  2. Внутреннее имя пользователя: Это фактическое имя пользователя, отправляемое внутри зашифрованного туннеля TTLS во время внутреннего процесса аутентификации (в вашем случае - PAP).

FreeRADIUS обрабатывает их через два отдельных виртуальных сервера:

  • Сервер default обрабатывает внешнюю аутентификацию
  • Сервер inner-tunnel обрабатывает внутреннюю аутентификацию

Внутреннее имя пользователя доступно на виртуальном сервере inner-tunnel, но его необходимо сохранить и передать обратно во внешнюю сессию для регистрации.

Необходимые изменения в конфигурации

Модификация виртуального сервера inner-tunnel

Сначала необходимо убедиться, что ваш виртуальный сервер inner-tunnel правильно настроен для захвата и сохранения внутреннего имени пользователя. Создайте или отредактируйте /etc/raddb/sites-enabled/inner-tunnel:

unlang
server inner-tunnel {
    authorize {
        # Ваши существующие модули authorize здесь
        # Убедитесь, что аутентификация PAP включена
        pap
    }

    authenticate {
        Auth-Type PAP {
            pap
        }
    }

    post-auth {
        # Обновите session-state для сохранения внутреннего имени пользователя
        # Это делает внутреннее имя пользователя доступным во внешней сессии
        update outer.session-state {
            &User-Name := &User-Name
        }
        
        # Опционально: Отдельно зарегистрируйте внутреннюю аутентификацию
        linelog inner_auth {
            filename = ${logdir}/custom/inner_auth.log
            reference = "messages.%{%{reply:Packet-Type}:-default}"
            
            messages {
                default = "timestamp=\"%t\" event=\"INNER-OTHER\" inner_user=\"%{User-Name}\" outer_user=\"%{outer.request:User-Name}\""
                Access-Accept = "timestamp=\"%t\" event=\"INNER-ACCEPT\" inner_user=\"%{User-Name}\" outer_user=\"%{outer.request:User-Name}\""
                Access-Reject = "timestamp=\"%t\" event=\"INNER-REJECT\" inner_user=\"%{User-Name}\" outer_user=\"%{outer.request:User-Name}\" reason=\"%{Module-Failure-Message}\""
            }
        }
        
        # Продолжите с существующими модулями post-auth
    }
}

Обновление конфигурации модуля linelog

Теперь измените конфигурацию log_access linelog, чтобы сослаться на сохраненное внутреннее имя пользователя:

unlang
linelog log_access {
    filename = ${logdir}/custom/log_access.log
    permissions = 0600

    reference = "messages.%{%{reply:Packet-Type}:-default}"

    messages {
        default = "timestamp=\"%t\" event=\"ACCESS-OTHER\" packet_type=\"%{Packet-Type}\" user=\"%{outer.session-state:User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
        
        Access-Accept = "timestamp=\"%t\" event=\"ACCESS-ACCEPT\" user=\"%{outer.session-state:User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
        Access-Reject = "timestamp=\"%t\" event=\"ACCESS-REJECT\" user=\"%{outer.session-state:User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" reason=\"%{Module-Failure-Message}\""
    }
}

Аналогично обновите вашу конфигурацию log_accounting:

unlang
linelog log_accounting {
    filename = ${logdir}/custom/log_accounting.log
    permissions = 0600

    reference = "messages.%{%{Acct-Status-Type}:-default}"

    messages {
        default = "timestamp=\"%t\" event=\"ACCT-OTHER\" acct_status=\"%{Acct-Status-Type}\" user=\"%{outer.session-state:User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" session_id=\"%{Acct-Session-Id}\""

        Start = "timestamp=\"%t\" event=\"ACCT-START\" user=\"%{outer.session-state:User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" session_id=\"%{Acct-Session-Id}\""
        Stop = "timestamp=\"%t\" event=\"ACCT-STOP\" user=\"%{outer.session-state:User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" session_id=\"%{Acct-Session-Id}\" duration_sec=\"%{Acct-Session-Time}\""
        
        Accounting-On = "timestamp=\"%t\" event=\"ACCT-ON\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
        Accounting-Off = "timestamp=\"%t\" event=\"ACCT-OFF\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
    }
}

Модификация конфигурации внешнего сервера

Обновите ваш сервер default для правильной обработки обновлений состояния сессии:

unlang
server default {
    # ... существующие конфигурации прослушивания ...

    authorize {
        eap {
            ok = return
        }

        pap
        
        update control {
            &Proxy-To-Realm := "authentik"
        }
    }

    authenticate {
        Auth-Type PAP {
            pap
        }

        eap
    }

    post-auth {
        # Обновите session-state для включения внутреннего имени пользователя
        update session-state {
            &Tmp-String-1 := "accept"
        }
        
        # Это скопирует внутреннее имя пользователя во внешнюю сессию
        if (&reply:EAP-Session-Id) {
            update reply {
                EAP-Key-Name := &reply:EAP-Session-Id
            }
        }
        
        log_access
        
        # Это гарантирует, что внутреннее имя пользователя доступно для конечного ответа
        update {
            &reply: += &session-state:
        }
    }

    post-proxy {
        eap
    }

    accounting {
        # Обновите учет для использования внутреннего имени пользователя
        update request {
            User-Name := "%{outer.session-state:User-Name}"
        }
        log_accounting
    }
}

Тестирование и проверка

После внесения этих изменений перезапустите FreeRADIUS и протестируйте аутентификацию. Ваши журналы теперь должны отображать внутреннее имя пользователя вместо “anonymous”:

Ожидаемый вывод в журнале:

# log_access.log
timestamp="Wed Nov  5 17:30:31 2025" event="ACCESS-ACCEPT" user="actual_user" client_mac="someid" nas_id="someid" nas_ip="10.0.5.x"
timestamp="Wed Nov  5 17:30:29 2025" event="ACCESS-ACCEPT" user="actual_user" client_mac="someid" nas_id="someid" nas_ip="10.0.5.x"

# log_accounting.log  
timestamp="Wed Nov  5 17:29:15 2025" event="ACCT-STOP" user="actual_user" client_mac="someid" nas_id="someid" nas_ip="10.0.5.x" session_id="4DCA6606E70B1D31" duration_sec="3333"
timestamp="Wed Nov  5 17:30:34 2025" event="ACCT-START" user="actual_user" client_mac="someid" nas_id="someid" nas_ip="10.0.5.x" session_id="02A4FDCAB6135746"

# Опциональный inner_auth.log
timestamp="Wed Nov  5 17:30:31 2025" event="INNER-ACCEPT" inner_user="actual_user" outer_user="anonymous"

Альтернативные подходы

Если приведенный выше подход не работает, попробуйте эти альтернативы:

Метод 1: Использование User-Name с nostrip

Убедитесь, что ваша конфигурация realm включает опцию nostrip для сохранения полного имени пользователя:

unlang
# В realms или sites-available/default
realm example.com {
    authhost = localhost
    accthost = localhost
    nostrip = yes
}

Метод 2: Использование Inner-Tunnel-User-Name

Некоторые версии FreeRADIUS поддерживают атрибут Inner-Tunnel-User-Name:

unlang
linelog log_access {
    # ... существующая конфигурация ...
    
    messages {
        Access-Accept = "timestamp=\"%t\" event=\"ACCESS-ACCEPT\" user=\"%{Inner-Tunnel-User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
        Access-Reject = "timestamp=\"%t\" event=\"ACCESS-REJECT\" user=\"%{Inner-Tunnel-User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\" reason=\"%{Module-Failure-Message}\""
    }
}

Метод 3: Использование разбора EAP-Message

В качестве запасного варианта можно разобрать EAP-Message для извлечения внутреннего имени пользователя:

unlang
# В разделе post-auth
update control {
    &Inner-User-Name := "%{mschap:User-Name}"
}

linelog log_access {
    messages {
        Access-Accept = "timestamp=\"%t\" event=\"ACCESS-ACCEPT\" user=\"%{control:Inner-User-Name}\" client_mac=\"%{Calling-Station-Id}\" nas_id=\"%{NAS-Identifier}\" nas_ip=\"%{NAS-IP-Address}\""
    }
}

Не забывайте тщательно тестировать после каждого изменения конфигурации и следить за журналами FreeRADIUS на предмет ошибок или сбоев аутентификации. Ключевым является обеспечение сохранения внутреннего имени пользователя через всю цепочку аутентификации и правильная ссылка на него в ваших конфигурациях журналирования.

Источники

  1. Документация FreeRADIUS - inner-tunnel
  2. Вики FreeRADIUS - ведение журнала eduroam
  3. Документация FreeRADIUS - модуль linelog
  4. Конфигурация EAP-TTLS FreeRADIUS
  5. Руководство по конфигурации EAP FreeRADIUS
  6. Обработка имени пользователя inner-tunnel FreeRADIUS
  7. Захват внутреннего имени пользователя EAP-TTLS FreeRADIUS

Заключение

Чтобы успешно регистрировать внутреннее имя пользователя из аутентификации EAP-TTLS/PAP в FreeRADIUS, вам необходимо:

  1. Настроить виртуальный сервер inner-tunnel для захвата и сохранения внутреннего имени пользователя с помощью update outer.session-state { &User-Name := &User-Name }

  2. Обновить ваши конфигурации linelog для ссылки на сохраненное внутреннее имя пользователя с помощью %{outer.session-state:User-Name} вместо просто %{User-Name}

  3. Изменить разделы post-auth и accounting внешнего сервера для правильной обработки обновлений состояния сессии

  4. Тщательно протестировать для правильной работы потока имени пользователя и его появления в журналах

Ключевое понимание заключается в том, что FreeRADIUS поддерживает отдельные пространства атрибутов для внутренней и внешней аутентификации, и вам явно нужно скопировать внутреннее имя пользователя во внешнее состояние сессии для целей ведения журналов. Этот подход обеспечивает безопасность при предоставлении подробных журналов аутентификации, необходимых для мониторинга и устранения неполадок.