Как работает система контроля доступа в Squid
Всем привет сегодня расскажу как работает система контроля доступа в Squid. Система контроля доступа Squid является достаточно мощным и развитым инструментом, позволяя гибко управлять самыми разными параметрами. В то же время многие администраторы имеют слабое понимание принципов работы данного механизма, что приводит к откровенным ошибкам или неожиданным результатам в работе прокси-сервера. Поэтому мы решили посвятить отдельный материал данному вопросу.
Система контроля доступа Squid состоит из двух различных частей: элементов ACL (ACL elements) и списков доступа (access lists). Здесь сокрыта первая сложность, которая связана с переводом на русский язык используемых терминов. Так ACL elements чаще всего переводится как ACL записи или ACL списки, что, в общем-то, достаточно верно отражает их смысл, но вызывает путаницу с термином access lists, вместо которого чаще всего используется термин правила ACL. Чаще всего путаница возникает при самостоятельном переводе англоязычной документации, что резко затрудняет понимание и приводит к различному рода казусам.
Элементы ACL
Под элементами ACL (они же записи или списки) подразумеваются списки значений определенного типа. Список допустимых типов представлен в документации: ACL TYPES AVAILABLE. Как видим, он довольно разнообразен, это и адреса источника или назначения, и доменные имена, параметры URL, время и дата, регулярные значение и т.д., и т.п. Каждый элемент ACL может содержать данные только одного допустимого типа, перечисленные через пробел или отдельной строкой. Также каждый элемент ACL должен иметь уникальное имя. Общий синтаксис следующий:
acl имя_acl тип_acl список_значений
Например, создадим элемент ACL содержащий IP-адреса какого-либо подразделения:
acl buh src 192.168.0.100-192.168.0.110 192.168.0.123
Также можно записать это следующим образом:
acl buh src 192.168.0.100-192.168.0.110
acl buh src 192.168.0.123
При выборе варианта написания следует исходить из его удобочитаемости, на наш взгляд второй вариант более удобен в восприятии, чем первый.
Одно и тоже значение может входить в списки сразу нескольких элементов ACL. Так один и тот же IP-адрес может входит в списки элементов buh (бухгалтерия), office (сеть офиса) и localnet (локальная сеть):
acl buh src 192.168.0.100-192.168.0.110 192.168.0.123
acl office src 192.168.0.100-192.168.0.230
acl localnet src 192.168.0.0/24
При этом абсолютно не важна последовательность указания элементов ACL в конфиге, в любом случае значение адреса будет входить во все три элемента. Определение принадлежности значения к элементу ACL производится по принципу ИЛИ, т.е. достаточно совпадения с одним из значений списка.
Однако мы советуем составлять списки элементов ACL таким образом, чтобы более частные случаи описывались перед более общими. А также записывать элементы одного типа в одном месте. В примере выше мы сначала указали сеть отдела, которая входит в сеть офиса, которая, в свою очередь, является частью локальной сети предприятия. Это делается для того, чтобы при анализе элементов ACL вы могли быстро оценить принадлежность значения спискам. Иначе можно потратить много времени на отладку, чтобы потом узнать, что значение входит в еще один элемент, который указан в другой части конфига.
Вы можете создать какое угодно количество элементов ACL, как говориться, на все случаи жизни, но при этом следует помнить, что все значения элементов загружаются в память при старте сервиса и каждое значение проверяется по каждому элементу соответствующего типа.
По времени работы различают два типа ACL: быстрые и медленные. К медленным относят элементы, связанные с необходимостью выполнять DNS-запросы, аутентификацию пользователей и т.д., с полным списком медленных и быстрых ACL можно ознакомиться здесь: Fast and Slow ACLs. По понятным причинам медленными элементами ACL злоупотреблять не следует.
Списки доступа
Элементы ACL сами по себе не осуществляют никаких действий, это просто списки, которые используются другой частью системы контроля доступа - списками доступа (или правилами). Перечень списков доступа также довольно обширен и полностью с ним можно ознакомиться здесь: Access Lists.
Общий синтаксис таков:
список_доступа действие (allow|deny) элементы_ACL
Вот здесь начинается самое интересное. Каждый список доступа может содержать несколько элементов ACL, которые обрабатываются по принципу И, т.е. чтобы список сработал, значение должно входить во все элементы ACL.
Сами списки обрабатываются последовательно, по принципу ИЛИ, т.е. до первого совпадения.
http_access allow|deny acl И acl И ...
ИЛИ
http_access allow|deny acl И acl И ...
ИЛИ
...
Если значение не попало ни в один список определенного типа, к нему применяется действие противоположное действию в последнем списке. Эта особенность способна привести к весьма неожиданному результату, поэтому хорошим тоном будет всегда задавать действие по умолчанию, указывая вместо элемента ACL значение all.
Простой пример. Сначала мы разрешили всем подразделениям доступ к интернету через протокол HTTP, но не задали при этом действия по умолчанию:
acl buh src 192.168.0.101-192.168.0.129
acl office src 192.168.0.101-192.168.0.199
acl sklad src 192.168.0.200-192.168.0.209
http_access allow buh
http_access allow office
http_access allow sklad
В приведенном примере всё будет работать как надо, все компьютеры, которые не относятся к указанным элементам ACL доступа к сети иметь не будут. А теперь мы решили заблокировать доступ к сети для склада:
http_access allow buh
http_access allow office
http_access deny sklad
После чего любой компьютер сети, кроме входящих в элемент sklad получит доступ, так как для всех не попавших в списки значений действие будет allow. Поэтому всегда задавайте действие по умолчанию:
http_access allow buh
http_access allow office
http_access deny sklad
http_access deny all
Часто возникает следующий вопрос, а можно ли вместо конструкции
http_access allow buh
http_access allow office
http_access allow sklad
написать
http_access allow buh office sklad
Вроде бы везде allow, зачем плодить строки? Ответ - нельзя! Потому что списки (правила) обрабатываются как ИЛИ, а элементы, как И. А так как один и тот же компьютер, несмотря на то, что сеть бухгалтерии входит в сеть офиса, не может одновременно принадлежать офису и складу, то такое правило работать не будет.
Очень простой пример:
acl ivanov src 192.168.0.123
acl petrov src 192.168.0.124
Если мы напишем так, то работать будет:
http_access allow ivanov
http_access allow petrov
так как читать эту конструкцию следует как:
http_access allow ivanov
ИЛИ
http_access allow petrov
А вот так не будет:
http_access allow ivanov petrov
потому что данная запись означает:
http_access allow ivanov И petrov
чего просто не может быть, так как источник может быть Ивановым ИЛИ Петровым, но никак не Ивановым И Петровым одновременно.
Вообще, избегайте сочетать в одном списке доступа элементы ACL одного типа, это самый верный способ получить нерабочее правило.
При указании списков доступа помните про очередность, поэтому все более частные правила должны располагаться перед более общими, даже если все эти списки доступа имеют одно и то же действие. Впоследствии вы можете поменять действие в одном из правил и получить совершенно неожиданный результат.
Поэтому правильно будет:
acl ivanov src 192.168.0.123
acl buh src 192.168.0.101-192.168.0.129
acl office src 192.168.0.101-192.168.0.199
http_access allow ivanov
http_access allow buh
http_access allow office
и неправильно:
http_access allow buh
http_access allow ivanov
http_access allow office
Допустим, поступила задача - ограничить доступ к интернету рабочим временем для всей бухгалтерии, кроме Иванова. Хорошо, добавляем:
acl worktime time MTWHF 09:00-18:00
Затем добавим к разрешающему списку второй элемент ACL и запретим работу во внерабочее время:
http_access allow buh worktime
http_access deny buh
В первом случае, когда список с элементом ivanov стоит выше списка с элементом buh - все будет работать как надо, а во втором случае нет. Так как адрес источника 192.168.0.123 входит в списки обоих элементов и условие для элемента buh сработает первым.
На первый взгляд это может показаться элементарным и очевидным, но на самом деле, когда правил много и расположены они вперемешку, поиск перекрывающихся списоков может занять много времени и потрепать немало нервов как вам, так и пользователям.
На примере выше мы неявно коснулись еще одной темы, при использовании перекрывающихся элементов ACL всегда создавайте списки для всех возможных сочетаний условий. Например, конструкция:
http_access allow ivanov
http_access allow buh worktime
http_access allow office
работать не будет, так как в рабочее время будет срабатывать правило http_access allow buh worktime, а в нерабочее http_access allow office, так как список значений элемента buh перекрывается списком значений элемента office. Чтобы все работало как задумано потребуется еще один список http_access deny buh:
http_access allow ivanov
http_access allow buh worktime
http_access deny buh
http_access allow office
Причем он должен располагаться строго на своем месте, передвинув его выше мы полностью заблокируем доступ для бухгалтерии, а передвинув ниже перекроем его действие разрешающим правилом для всего офиса.
Также, как и элементы ACL списки доступа могут быть быстрыми и медленными: Fast and Slow ACLs. Например, списки доступа delay_access, отвечающие за ограничение скорости, являются быстрыми, аhttp_access - медленными. Общее правило: использовать быстрые списки раньше медленных и не использовать быстрые списки с медленными элементами. Также имеет смысл вводить некоторые "бесполезные" проверки, чтобы уменьшить количество обращений к медленным спискам с медленными элементами.
Материал сайта pyatilistnik.org