![](https://habrastorage.org/webt/ww/gy/7r/wwgy7relk4bkn9y8crew8gh6sxc.jpeg)
Во многих организациях структура сети предполагает использование терминальных серверов, персональных компьютеров, а также мобильных устройств. В данной публикации пойдет речь о том, как все это пустить через прокси сервер Squid, не прописывая лишний раз настройки браузера на каждом устройстве. Статей по настройке Squid есть много, но везде по кусочкам. Я решил собрать всё в кучу, и описать рабочую конфигурацию от начала и до конца.
На терминальных серверах будем использовать Explicit Proxy с авторизацией на основе групп Active Directory (сервера должны находиться в домене, и пользователи должны подключаться к ним по доменным учетным записям). Для устройств — Interception Proxy авторизация будет основываться на MAC адресах, это позволит нам гибче настраивать правила доступа, не привязываясь к диапазонам ip адресов.
![](https://habrastorage.org/webt/dh/dz/2l/dhdz2lf0o46hsaxumr_hdayxzxo.jpeg)
Использовать будем CentOS Linux 7.X.XXX и Squid 4.0.23.
Во избежание путаницы, Explicit Proxy — «непрозрачный» прокси сервер, при котором в браузере клиента указывается адрес прокси-сервера, Interception Proxy — «прозрачный» режим, когда на клиенте в качестве шлюза указывается прокси-сервер, а сам браузер ничего об этом не знает.
Squid будет прослушивать 3 порта:
- port 3127 – для HTTPS трафика при Interception Proxy. То есть на этот порт мы будем с помощью iptables перенаправлять HTTPS запросы от клиентов на которых в качестве шлюза прописан прокси сервер;
- port 3128 – для HTTP и HTTPS трафика при Explicit Proxy. В данном случае разделения HTTP
и HTTPS портов не нужно, потому как браузер понимает, что он работает через прокси сервер;
- port 3129 – для HTTP трафика при Interception Proxy. То есть на этот порт мы будем с помощью iptables перенаправлять HTTP запросы от клиентов на которых в качестве шлюза прописан прокси сервер.
Предварительная настройка
У нас есть два Ethernet интерфейса: eth0 – смотрит в локальную сеть, eth1 – смотрит в глобальную сеть. В случае, который будет описан ниже терминальные сервера и устройства расположены в сети 192.168.0.0/24. Прокси сервер имеет адрес 192.168.0.133.
Приводим файл настроек /etc/sysconfig/network-scripts/ifcfg-eth0 к такому виду (значения подставляем свои):
TYPE=Ethernet
BOOTPROTO=none
DEFROUTE=no
PEERDNS=yes
PEERROUTES=no
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
IPV6_FAILURE_FATAL=no
NAME=eth0
UUID=f34ec600-6c46-485f-9216-0fd8954a9013
DEVICE=eth0
ONBOOT=yes
USERCTL=NO
NM_CONTROLLED=no
IPADDR=192.168.0.133
NETMASK=255.255.255.0
DNS1=192.168.0.19
DNS2=192.168.0.18
DOMAIN=balt.local
SEARCH=balt.local
В директивах DOMAIN и SEARCH нужно указать свое имя домена.
Приводим файл настроек /etc/sysconfig/network-scripts/eth1 к такому виду (значения подставляем свои):
TYPE=Ethernet
BOOTPROTO=none
DEFROUTE=yes
PEERDNS=no
PEERROUTES=no
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
IPV6_FAILURE_FATAL=no
NAME=eth1
UUID=2e6072a6-a5fd-4f39-8786-501fa14e6015
DEVICE=eth1
ONBOOT=yes
USERCTL=no
NM_CONTROLLED=no
IPADDR=112.132.114.190
NETMASK=255.255.255.252
GATEWAY=112.132.114.189
Задаем имя хоста:
# hostnamectl set-hostname SRV-M29-PRX-03
Прописываем на DNS сервере A запись для прокси сервера, чтобы он резолвился из локальной сети.
Если локальная сеть состоит из подсетей, то чтобы они могли взаимодействовать между собой на устройствах с прокси сервером в качестве шлюза, нужно настроить маршруты и включить форвардинг.
Создаем файл /etc/sysconfig/network-scripts/route-eth0 и добавляем в него требуемые маршруты, например:
192.168.0.0/24 via 192.168.0.78 dev eth0
192.168.2.0/24 via 192.168.0.78 dev eth0
192.168.3.0/24 via 192.168.0.78 dev eth0
10.254.253.0/24 via 192.168.0.78 dev eth0
Добавляем в /etc/sysctl.conf:
net.ipv4.ip_forward = 1
Перезагружаемся.
Настраиваем фаервол. Squid 4.X.XX работает и с firewalld и с iptables. Кому как удобнее. В этой статье используем iptables.
Останавливаем и удаляем firewalld:
# systemctl stop firewalld
# yum remove firewalld.noarch
Устанавливаем и запускаем iptables:
# yum install iptables-services
# systemctl enable iptables
# systemctl enable ip6tables
# systemctl start iptables
# systemctl start ip6tables
Разрешаем SSH и ICMP только с локальной сети:
# iptables -R INPUT 4 -i eth0 -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
# iptables -R INPUT 2 -i eth0 -p icmp -j ACCEPT
Настраиваем перенаправления трафика с http 80 и https 443 портов на соответствующие сквидовские 3129 и 3127. Также используем ipset для создания списка адресов назначения, которые не будут перенаправляться на Squid, а будут проходить мимо него. Это нужно, например, для банк-клиентов, для telegram’а и т.д.
Создаем список исключений:
# ipset create no_proxy_net_dst hash:net
Добавляем в него нужные нам адреса. Например, чтобы не проксировать трафик telegram’a с устройств указываем:
# ipset add no_proxy_net_dst 149.154.160.0/20
Созданные настройки ipset сотрутся после перезагрузки, что также повлечет за собой сбой запуска iptables. Поэтому пишем скрипт восстановления данных правил после перезагрузки.
Выгружаем ipset настройки в файл:
# ipset save -file /etc/sysconfig/ipset-lists.conf
Создаем скрип /usr/scripts/system/ipset-restore.bash, который при загрузке сначала затирает все правила, и после восстанавливает конфигурацию с /etc/sysconfig/ipset-lists.conf:
#!/bin/bash
ipset destroy
ipset restore -file /etc/sysconfig/ipset-lists.conf
Данный скрипт должен запускаться перед стартом iptables, поэтому в сервис /etc/systemd/system/basic.target.wants/iptables.service добавляем строчку:
ExecStartPre=/usr/scripts/system/ipset-restore.bash
Перезагружаем systemd:
# systemctl daemon-reload
Создаем правила редиректа в iptables:
# iptables -t nat -A PREROUTING -p tcp -m tcp -s 192.168.0.0/24 --dport 443 -m set ! --match-set no_proxy_net_dst dst -j REDIRECT --to-ports 3127
# iptables -t nat -A PREROUTING -p tcp -m tcp -s 192.168.0.0/24 --dport 80 -m set ! --match-set no_proxy_net_dst dst -j REDIRECT --to-ports 3129
То есть весь http и https трафик из сети 192.168.0.0/24, за исключением того, чей адрес назначения указан в no_proxy_net_dst, отправляем на Squid.
Редактируем цепочку FORWARD, разрешаем свободно ходить пакетам внутри локальной сети между всеми подсетями, а также из сети 192.168.0.0/24 ходить через WAN интерфейс eth1.
# iptables -I FORWARD 1 -i eth0 -o eth0 -p all -j ACCEPT
# iptables -I FORWARD 2 -i eth0 -o eth1 -s 192.168.0.0/24 -j ACCEPT
# iptables -I FORWARD 3 -i eth1 -o eth0 -d 192.168.0.0/24 -j ACCEPT
Настраиваем SNAT на eth1:
# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth1 -j SNAT --to-source 112.132.114.190
Ну и открываем нужные нам порты на внутреннем интерфейсе:
# iptables -I INPUT 1 -i eth0 -p tcp --dport 80 -j ACCEPT
# iptables -I INPUT 1 -i eth0 -p tcp --dport 443 -j ACCEPT
# iptables -I INPUT 1 -i eth0 -p tcp --dport 3127 -j ACCEPT
# iptables -I INPUT 1 -i eth0 -p tcp --dport 3128 -j ACCEPT
# iptables -I INPUT 1 -i eth0 -p tcp --dport 3129 -j ACCEPT
Сохраняем конфигурацию iptables:
# /sbin/iptables-save > /etc/sysconfig/iptables
Также можно, для спокойствия, указать ssh слушать только на внутреннем интерфейсе. Редактируем /etc/ssh/sshd_config:
ListenAddress 192.168.0.133
Аутентифицироваться в AD мы будем с помощью Kerberos. Этот протокол требует, чтобы время в сети было синхронизировано. Поэтому настраиваем прокси сервер для получения информации о времени с контролеров домена. Будем использовать NTP.
Устанавливаем:
# yum install ntp
Редактируем файл конфигурации /etc/ntp.conf, вместо серверов centos.pool.ntp.org указываем наши:
server srv-m29-dc-03.balt.local iburst
server srv-m29-dc-01.balt.local iburst
И указываем использовать только внутренний интерфейс:
interface ignore wildcard
interface listen 192.168.0.133
interface ignore ipv6
Запускаем:
# systemctl enable ntpd
# systemctl start ntpd
Проверить работу можно с помощью команд:
# ntpq -4 -c peers
# ntpstat
Знаю, что отключать SELinux неправильно, но до настройки Squid и SELinux у меня пока руки не дошли. В скором времени планирую вернуться к этому вопросу. Поэтому я отключаю SELinux, но ни в коем случае не агитирую это делать остальным. Если есть время, лучше будет и для вас, и для Дэна Уолша, разобраться и сделать правильно.
Переводим SELinux в Permissive режим работы, редактируем файл /etc/sysconfig/selinux:
SELINUX=permissive
Перезагружаемся.
Установка Squid
Подготовительная часть закончилась. Теперь приступаем к установке Squid.
В официальных репозиториях CentOS есть только Squid 3.5. Мы же будем ставить Squid 4.0.23.
Поэтому качаем сам Squid:
# wget http://www1.ngtech.co.il/repo/centos/7/beta/x86_64/squid-debuginfo-4.0.23-1.el7.centos.x86_64.rpm
# wget http://www1.ngtech.co.il/repo/centos/7/beta/x86_64/squid-debuginfo-4.0.23-1.el7.centos.x86_64.rpm
Хелперы к нему:
# wget http://www1.ngtech.co.il/repo/centos/7/beta/x86_64/squid-helpers-4.0.23-1.el7.centos.x86_64.rpm
Хелперы это скрипты, которые добавляют в Squid те или иные функции. Например, мы будем использовать ext_kerberos_ldap_group_acl, с помощью которого будет проверять принадлежность пользователя к группе в Active Directory.
Ставим зависимости:
# wget http://www1.ngtech.co.il/repo/centos/7/x86_64/libecap-1.0.0-3.el7.centos.x86_64.rpm
# wget http://www1.ngtech.co.il/repo/centos/7/x86_64/libecap-debuginfo-1.0.0-3.el7.centos.x86_64.rpm
# wget http://www1.ngtech.co.il/repo/centos/7/x86_64/libecap-devel-1.0.0-3.el7.centos.x86_64.rpm
# yum -y --nogpgcheck localinstall libecap-1.0.0-3.el7.centos.x86_64.rpm
# yum -y --nogpgcheck localinstall libecap-devel-1.0.0-3.el7.centos.x86_64.rpm
# yum -y --nogpgcheck localinstall libecap-debuginfo-1.0.0-3.el7.centos.x86_64.rpm
# yum install libtool-ltdl openssl-devel cyrus-sasl-gssapi gnutls epel-release perl-Crypt-OpenSSL-X509 perl-DBI perl-Digest-MD5 perl-URI gcc gcc-c++ perl-Digest-SHA
Устанавливаем Squid:
# rpm -Uhv squid-4.0.23-1.el7.centos.x86_64.rpm
# rpm -Uhv squid-debuginfo-4.0.23-1.el7.centos.x86_64.rpm
# rpm -Uhv squid-helpers-4.0.23-1.el7.centos.x86_64.rpm
Изменяем владельца каталогов, которые используются сквидом:
# chown -R squid:squid /var/spool/squid/
# chown -R squid:squid /usr/bin/squidclient
# chown -R squid:squid /etc/squid/
# chown -R squid:squid /usr/share/squid
# chown -R squid:squid /usr/lib64/squid
# chown -R squid:squid /var/log/squid/
Изменим немного дефолтную конфигурацию /etc/squid/squid.conf:
acl localnet src fe80::/10 # RFC 1918 local private network (LAN)
# локальная сеть
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
# Запретить доступ портам
http_access deny !Safe_ports
# Запретить CONNECT к не SSL портам
http_access deny CONNECT !SSL_ports
# Разрешить cachemgr доступ только с локального хоста
http_access allow localhost manager
http_access deny manager
# Разрешаем доступ с localhost
http_access allow localhost
# Запрезаем все, что не разрешено
http_access deny all
# Интерфейсы и порты на которых будет слушать Squid
http_port 192.168.0.133:3128
# Настройки DNS. Без них может медленно работать
dns_nameservers 192.168.1.2 192.168.0.18
dns_v4_first on
# Настройки кеша
cache_dir ufs /var/spool/squid 100 16 256
coredump_dir /var/spool/squid
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
Корректность отредактированного файла конфигурации можно проверить с помощью:
# squid -k parse
В настройках мы указали, что будем использовать кэширование. Поэтому нужно создать дерево каталогов, в котором наш кэш будет хранится. Выполняем команду:
# squid -z
И стартуем Squid:
# systemctl enable squid
# systemctl start squid
Настройка Explicit Proxy
Дефолтная конфигурация предусматривает работу «непрозрачного» прокси с авторизацией на основе ip адресов – разрешен выход в Интернет всем компьютерам локальной сети.
Нас же интересует аутентификация в домене Active Directory с авторизацией на основе доменных групп. Для аутентификации в AD будем использовать протокол Kerberos. В этом нам поможет хелпер negotiate_kerberos_auth. Для авторизации по группам будем использовать хелпер ext_kerberos_ldap_group_acl.
Для начала устанавливаем Kerberos клиент:
# yum install krb5-workstation
Нужно создать пользователя в Active Directory. Пускай это будет admin_squid. У данного пользователя должно быть право на чтение принадлежности пользователей домена к доменным группам. Поэтому добавим пользователя, например, в группу Organization Managment.
! UPD: В большинстве конфигураций все пользователи имеют данное право, поэтому какие-либо дополнительные группы добавлять не нужно. Если это не так, то лучше использовать группу с более ограниченными правами чем "Organization Managment"
Генерируем keytab-файл на контроллере домена. Этот файл используется для аутентификации в инфраструктуре Kerberos. При этом пользователям не нужно будет вводить логин и пароль, Squid сам будет их аутентифицировать с помощью keytab-файла.
# ktpass -princ HTTP/srv-m29-prx-03.balt.local@BALT.LOCAL -mapuser BALT\admin_squid -pass 3EYldza1sR -crypto All -ptype KRB5_NT_PRINCIPAL -out C:\keytabs\PROXY.keytab
!UPD: опцию "crypto" указываем согласно своих настроек безопасности.
princ, mapuser, pass, out естественно меняем на свои. Итоговый файл PROXY.keytab нужно скопировать на прокси-сервер в /etc/squid и изменить на него права:
# chown squid:squid /etc/squid/PROXY.keytab
# chmod 640 /etc/squid/PROXY.keytab
Редактируем файл конфигурации Kerberos на прокси-сервере /etc/krb5.conf:
includedir /etc/krb5.conf.d/
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
rdns = false
default_realm = BALT.LOCAL
default_ccache_name = KEYRING:persistent:%{uid}
default_keytab_name = /etc/squid/PROXY.keytab
[realms]
BALT.LOCAL = {
kdc = srv-m29-dc-03.balt.local
kdc = srv-m29-dc-01.balt.local
admin_server = srv-m29-dc-03.balt.local
default_domain = balt.local
}
[domain_realm]
.balt.local = BALT.LOCAL
balt.local = BALT.LOCAL
Здесь,
default_realm, default_domain – FQDN домена
default_keytab_name – путь к keytab-файлу
kdc, admin_server – контроллеры домена
Проверяем:
# kinit -kV -p HTTP/srv-m29-prx-03.balt.local
Если все правильно, то получим в ответ «Authenticated to Kerberos v5».
Удалим полученный ticket, который мы получили от сервера Kerberos на предыдущем шаге:
# kdestroy
Теперь вносим изменения в «squid startup script» /etc/sysconfig/squid, чтобы squid знал где лежит keytab-файл:
KRB5_KTNAME=/etc/squid/PROXY.keytab
export KRB5_KTNAME
Добавляем в /etc/squid/squid.conf:
auth_param negotiate program /usr/lib64/squid/negotiate_kerberos_auth -s HTTP/srv-m29-prx-03.balt.local
auth_param negotiate children 10
auth_param negotiate keep_alive on
Данные строчки должны быть в начале файла перед всеми acl. Они описывают собственно аутентификацию с помощью Kerberos. Информацию о параметрах auth_param можно узнать по ссылке auth_param.
Также добавляем acl, который соответствует всем прошедшим Kerberos-проверку пользователям и разрешаем им доступ:
acl kerb_auth proxy_auth REQUIRED
http_access allow kerb_auth
Указываем Squid’у перечитать конфигурацию:
# squid -k reconfigure
После данных манипуляций пользователи с доменными учетными записями могут выходить в Интернет. Указываем на терминальных серверах в браузере srv-m29-prx-03.balt.local, порт 3128 в параметрах прокси сервера и проверяем. На данном этапе мы уже можем создавать правила доступа для каждой доменной учетной записи. Например, если мы хотим пользователю petrov.e запретить вход на gmail.com, то добавляем в конфигурацию:
acl petrov-e proxy_auth petrov.e@BALT.LOCAL
acl gmail url_regex -i mail\.google\.com
acl gmail url_regex -i gmail\.com
http_access deny petrov-e gmail
Также нас интересует авторизация по группам. Для этого создаем в AD нужные группы:
SQUID-INTERNET-STANDART
– стандартная группа, для которой ограничен вход на запрещенные в компании сайты
SQUID-INTERNET-FULL-ACCESS
– группа, для которой разрешен вход на любые сайты
SQUID-INTERNET-EXTENDED
– группа, для которой список разрешенных сайтов более широкий, чем для SQUID-INTERNET-STANDART
Также создадим файлы на прокси-сервере, и внесем в них список требуемых нам сайтов:
blocked-http.txt
– список запрещенных http/https сайтов
allowed-http-always.txt
– список всегда разрешенных http/https сайтов (например, если корпоративный портал должен быть доступен всем без исключения)
allowed-http-extended.txt
– список дополнительных разрешенных сайтов для группы SQUID-INTERNET-EXTENDED.
Добавим, для примера, в blocked-http.txt сайт msn.com и vk.com:
www\.msn\.com
vk\.com
В вышеуказанных файлах ссылки на сайты указываются с помощью регулярных выражений.
Настраиваем Squid для проверки вхождения пользователя в доменную группу. Для этого будем использовать хелпер ext_kerberos_ldap_group_acl. Добавляем в /etc/squid/squid.conf:
external_acl_type SQUID-INTERNET-FULL_ACCESS ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-FULL_ACCESS -D BALT.LOCAL
external_acl_type SQUID-INTERNET-EXTENDED ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-EXTENDED -D BALT.LOCAL
external_acl_type SQUID-INTERNET-STANDART ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-STANDART -D BALT.LOCAL
acl SQUID-INTERNET-FULL_ACCESS external SQUID-INTERNET-FULL_ACCESS
acl SQUID-INTERNET-STANDART external SQUID-INTERNET-STANDART
acl SQUID-INTERNET-EXTENDED external SQUID-INTERNET-EXTENDED
Опять же, что такое external_acl_type можно почитать external_acl_type, потому как данная статья и так большая. Имя контролера домена srv-m29-dc-03 и имя домена BALT.LOCAL подставляем свои.
Описываем acl с http/https адресами:
acl allowed-http-always url_regex -i "/etc/squid/allowed-http-always.txt"
acl blocked-http url_regex -i "/etc/squid/blocked-http.txt"
acl allowed-http-extended url_regex -i "/etc/squid/allowed-http-extended.txt"
И создаем правила на основании этих acl:
http_access allow allowed-http-always
http_access allow SQUID-INTERNET-FULL_ACCESS
http_access allow SQUID-INTERNET-EXTENDED allowed-http-extended
http_access allow SQUID-INTERNET-EXTENDED !blocked-http
http_access allow SQUID-INTERNET-STANDART !blocked-http
Комментируем строчку http_access allow kerb_auth, так как нам уже не нужно чтобы любой зарегистрированный на сервере пользователь мог выходить куда угодно.
Конечный squid.conf должен быть примерно такого вида:
#параметры аутентификации Kerberos
auth_param negotiate program /usr/lib64/squid/negotiate_kerberos_auth -s HTTP/srv-m29-prx-03.balt.local
auth_param negotiate children 10
auth_param negotiate keep_alive on
# локальная сеть
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
#внешние acl, для проверки вхождения пользователя в группу
external_acl_type SQUID-INTERNET-FULL_ACCESS ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-FULL_ACCESS -D BALT.LOCAL
external_acl_type SQUID-INTERNET-EXTENDED ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-EXTENDED -D BALT.LOCAL
external_acl_type SQUID-INTERNET-STANDART ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-STANDART -D BALT.LOCAL
acl SQUID-INTERNET-FULL_ACCESS external SQUID-INTERNET-FULL_ACCESS
acl SQUID-INTERNET-STANDART external SQUID-INTERNET-STANDART
acl SQUID-INTERNET-EXTENDED external SQUID-INTERNET-EXTENDED
#списки сайтов
acl allowed-http-always url_regex -i "/etc/squid/allowed-http-always.txt"
acl blocked-http url_regex -i "/etc/squid/blocked-http.txt"
acl allowed-http-extended url_regex -i "/etc/squid/allowed-http-extended.txt"
# acl, который соответствует все доменным учетным записям, прошедшим проверку
acl kerb_auth proxy_auth REQUIRED
#http_access allow kerb_auth
# Запретить доступ к небезопасным портам
http_access deny !Safe_ports
# Запретить CONNECT к небезопасным SSL портам
http_access deny CONNECT !SSL_ports
# Разрешить cachemgr доступ только с локального хоста
http_access allow localhost manager
http_access deny manager
# Разрешаем доступ с localhost
http_access allow localhost
#разрешаем доступ на основании доменных групп
http_access allow allowed-http-always
http_access allow SQUID-INTERNET-FULL_ACCESS
http_access allow SQUID-INTERNET-EXTENDED allowed-http-extended
http_access allow SQUID-INTERNET-EXTENDED !blocked-http
http_access allow SQUID-INTERNET-STANDART !blocked-http
# Запрещаем все, что не разрешено
http_access deny all
# Интерфейсы и порты на которых будет слушать Squid
http_port 192.168.0.133:3128
# Настройки DNS. Без них может медленно работать
dns_nameservers 192.168.1.2 192.168.0.18
dns_v4_first on
# Настройки кэша
cache_dir ufs /var/spool/squid 100 16 256
coredump_dir /var/spool/squid
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
Перегружаем Squid:
# systemctl restart squid
После данных манипуляций, если пользователь входит в доменную группу SQUID-INTERNET-STANDART, ему будет запрещен вход на сайты msn.com и vk.com. Пользователям, которые не входят ни в одну из групп, выход в Интернет будет запрещен совсем.
На этом настройка Explicit Proxy завершена.
Настройка Interception Proxy
С настройкой прокси сервера для доменных пользователей разобрались, с помощью групповых политик теперь задаем на терминальных серверах адрес прокси сервера и пользуемся. Но для компьютеров, не входящих в домен, и для разных мобильных устройств групповые политики не работают, а прописывать каждый раз вручную настройки прокси не удобно. И даже если прописать, то, например, придя домой с устройством, выхода в Интернет с него не будет. Поэтому нужно дополнительно настроить «прозрачный» прокси сервер. Можно выделить диапазон ip адресов, и для него создавать правила в Squid’е, но удобнее (для меня) использовать MAC адреса устройств.
Для этого создаем списки mac адресов (это будет аналог доменных групп, которые мы создавали ранее для Explicit Proxy):
/etc/squid/ allowed-mac.txt
– сюда входят устройства со стандартным доступом
/etc/squid/allowed-mac-extended.txt
– сюда входят устройства с расширенным доступом
/etc/squid/allowed-mac-full-access.txt
– сюда входят устройства с полным доступом
В файлах каждое новое устройство должно быть указано в новой строке. Комментарии начинаются с символа #. Например, у меня это выглядит так:
##Сергей Орлов (TEL)
94:E9:6A:D3:E0:CB
##Сергей Орлов (NB) (Wi-Fi)
24:0A:64:74:2D:71
Дальше нужны дополнительные настройки для «прозрачного» проксирования https трафика. При переходе на https сайт в логах будет отображаться только запрос CONNECT, то есть мы не увидим куда именно пользователь заходил на этом сайте. Чтобы увидеть активность более детально нужно разрывать TLS соединение, фактически реализовывая «man-in-the-middle» атаку. Поэтому, если хочется мониторить что именно пользователь делал на https ресурсе, нужно на его устройство устанавливать самоподписанный сертификат прокси-сервера. В ином случае никаких дополнительных действий на стороне клиента не нужно.
Создаем публичные и приватные ключи для самоподписанных CA сертификатов. Squid будет их использовать для генерации динамических сертификатов для сайтов, которые запрашивают клиенты.
Создаем директорию для сертификата:
# mkdir /etc/squid/ssl_cert
# chown -R squid:squid /etc/squid/ssl_cert/
# chmod 700 /etc/squid/ssl_cert
# cd /etc/squid/ssl_cert
Генерируем его:
# openssl req -new -newkey rsa:2048 -sha256 -days 365 -nodes -x509 -extensions v3_ca -keyout myCA.pem -out myCA.pem
Вводим свои данные.
Генерируем также сертификат для установки на клиентских устройствах, если потребуется прослушка https:
# openssl x509 -in myCA.pem -outform DER -out srv-m29-prx-03.der
На стороне клиента его нужно устанавливать в доверенные корневые сертификаты.
Создаем директорию для динамических сертификатов. Для этого используем хелпер ssl_crtd:
# /usr/lib64/squid/security_file_certgen -c -s /etc/squid/ssl_db -M 4MB
# chown -R squid:squid /etc/squid/ssl_db/
Создаем списки https сайтов:
/etc/squid/blocked_https.txt
– заблокированные https сайты
/etc/squid/allowed-https-extended.txt
– дополнительные разрешенные https сайты
/etc/squid/allowed-https-always.txt
– всегда разрешенные https сайты
/etc/squid/monitored-https.txt
– сайты, трафик которых мы хотим расшифровывать
Правим конфиг /etc/squid/squid.conf.
Указываем в squid.conf работать Interception Proxy на портах 3127 для https и 3129 для http.
http_port 192.168.0.133:3129 intercept
https_port 192.168.0.133:3127 intercept ssl-bump cert=/etc/squid/ssl_cert/myCA.pem generate-host-certificates=on dynamic_cert_mem_cache_size=4MB
Создаем acl для https трафика и MAC адресов:
acl allowed-mac arp "/etc/squid/allowed-mac.txt"
acl allowed-mac-extended arp "/etc/squid/allowed-mac-extended.txt"
acl allowed-mac-full-access arp "/etc/squid/allowed-mac-full-access.txt"
acl step1 at_step SslBump1
acl allowed-https-always ssl::server_name_regex -i "/etc/squid/allowed-https-always.txt"
acl blocked-https ssl::server_name_regex -i "/etc/squid/blocked-https.txt"
acl allowed-https-extended ssl::server_name_regex -i "/etc/squid/allowed-https-extended.txt"
acl monitored-HTTPS ssl::server_name_regex -i "/etc/squid/monitored-HTTPS.txt"
Добавляем разрешающие правила для устройств и http трафика:
http_access allow allowed-mac-full-access
http_access allow allowed-mac-extended allowed-http-extended
http_access allow allowed-mac-extended !blocked-http
http_access allow allowed-mac !blocked-http
Добавляем разрешающие правила для устройств и https трафика:
ssl_bump peek step1
ssl_bump bump allowed-mac-full-access monitored-HTTPS
ssl_bump bump allowed-mac-extended monitored-HTTPS
ssl_bump bump allowed-mac monitored-HTTPS
ssl_bump splice allowed-https-always
ssl_bump splice allowed-mac-full-access
ssl_bump splice allowed-mac-extended allowed-https-extended
ssl_bump splice allowed-mac-extended !blocked-https
ssl_bump splice allowed-mac !blocked-https
ssl_bump terminate all
И настройки для создания динамический сертификатов:
sslcrtd_program /usr/lib64/squid/security_file_certgen -s /etc/squid/ssl_db -M 4MB
Перезагружаем Squid.
Если теперь на устройстве прописать в качестве шлюза наш прокси сервер, то все должно заработать, без установки каких-либо сертификатов на стороне клиента.
Немного о проксировании https. В Squid 3.5 и выше для этих целей используется так называемая фича SslBump Peek and Splice. Суть ее заключается в том, что Squid «подсматривает» процесс TLS рукопожатия, когда уже известные клиентский SNI и сертификат веб-сервера, отправленный в ответ на запрос клиента. SNI – это имя хоста, с которым клиент желает установить TLS соединение. На основании этих данных можно решить что Squid будет делать дальше – блокировать или пропускать.
Фактически, Squid просматривает TLS Client Hello сообщение, создает идентичное, и отправляет его веб-серверу назначения. Сервер отвечает TLS Server Hello сообщением, который также можно проанализировать.
То есть имеем три этапа (шага):
- получаем CONNECT от клиента. На этом шаге нам не известно доменное имя запрашиваемого сайта. Только tcp-level информация — ip адрес и порт. Поэтому принимать решения, основываясь на доменном имени сейчас невозможно;
- получаем tls client hello от клиента. Здесь уже есть SNI, то есть уже известно имя сервера назначения;
- получаем tls server hello от сервера, который имеет сертификат сервера.
На каждом шаге мы можем выполнить одно из 5-ти действий: peek, splice, stare, bump, terminate. От того на каком шаге выполняется какое действие зависит дальнейшая обработка соединения. Описывать все я не буду, так как получится много текста. Почитать что и как можно здесь SslPeekAndSplice.
Опишу только касательно нашей конфигурации.
Строка «acl step1 at_step SslBump1» как раз описывает первых шаг.
Строка «ssl_bump peek step1» значит выполнить на первом шаге peek, результатом которого будет переход к второму шагу, где мы обрабатываем TLS Client Hello и извлекаем SNI.
Строки:
ssl_bump bump allowed-mac-full-access monitored-HTTPS
ssl_bump bump allowed-mac-extended monitored-HTTPS
ssl_bump bump allowed-mac monitored-HTTPS
говорят, если имя сервера извлеченное из SNI есть в файле monitored-https.txt и mac адрес устройства клиента есть в разрешенных списках, то устанавливаем TLS соединение с сервером (используя клиентских SNI) и устанавливаем TLS соединение с клиентом (используя поддельный динамический сертификат сервера). То есть фактически организовываем «squid-in-the-middle». Так как сертификат для клиента поддельный, браузер будет ругаться. Для этого мы и создавали выше сертификат srv-m29-prx-03.der, который нужно установить на устройство клиента.
Строки:
ssl_bump splice allowed-https-always
ssl_bump splice allowed-mac-full-access
ssl_bump splice allowed-mac-extended allowed-https-extended
ssl_bump splice allowed-mac-extended !blocked-https
ssl_bump splice allowed-mac !blocked-https
говорят, если имя сервера извлеченное из SNI есть в разрешенных файлах с https списками, то создаем tcp туннель без декодирования соединения. То есть клиент и сервер общаются напрямую, как будто между ними нет никакого прокси сервера. Браузер получает нормальный сертификат от веб-сервера, а не поддельный от прокси сервера, и естественно не ругается.
В итоге, если нам нужно дешифровать TLS соединение, то самоподписанный сертификат прокси сервера нужно устанавливать на устройство. Если нужно просто решить пускать ли нам клиента на сайт, или нет, без логов активности на этом сайте, то сертификат можно не устанавливать.
Итоговая конфигурация:
#параметры аутентификации Kerberos
auth_param negotiate program /usr/lib64/squid/negotiate_kerberos_auth -s HTTP/srv-m29-prx-03.balt.local
auth_param negotiate children 10
auth_param negotiate keep_alive on
# локальная сеть
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
#внешние acl, для проверки вхождения пользователя в группу
external_acl_type SQUID-INTERNET-FULL_ACCESS ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-FULL_ACCESS -D BALT.LOCAL
external_acl_type SQUID-INTERNET-EXTENDED ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-EXTENDED -D BALT.LOCAL
external_acl_type SQUID-INTERNET-STANDART ttl=300 negative_ttl=60 %LOGIN /usr/lib64/squid/ext_kerberos_ldap_group_acl -a -m 0 -S srv-m29-dc-03 -g SQUID-INTERNET-STANDART -D BALT.LOCAL
acl SQUID-INTERNET-FULL_ACCESS external SQUID-INTERNET-FULL_ACCESS
acl SQUID-INTERNET-STANDART external SQUID-INTERNET-STANDART
acl SQUID-INTERNET-EXTENDED external SQUID-INTERNET-EXTENDED
#списки сайтов http
acl allowed-http-always url_regex -i "/etc/squid/allowed-http-always.txt"
acl blocked-http url_regex -i "/etc/squid/blocked-http.txt"
acl allowed-http-extended url_regex -i "/etc/squid/allowed-http-extended.txt"
#списки https сайтов
acl allowed-https-always ssl::server_name_regex -i "/etc/squid/allowed-https-always.txt"
acl blocked-https ssl::server_name_regex -i "/etc/squid/blocked-https.txt"
acl allowed-https-extended ssl::server_name_regex -i "/etc/squid/allowed-https-extended.txt"
acl monitored-HTTPS ssl::server_name_regex -i "/etc/squid/monitored-HTTPS.txt"
#списки устройств
acl allowed-mac arp "/etc/squid/allowed-mac.txt"
acl allowed-mac-extended arp "/etc/squid/allowed-mac-extended.txt"
acl allowed-mac-full-access arp "/etc/squid/allowed-mac-full-access.txt"
acl step1 at_step SslBump1
# acl, который соответствует все доменным учетным записям, прошедшим проверку
acl kerb_auth proxy_auth REQUIRED
#http_access allow kerb_auth
# Запретить доступ к небезопасным портам
http_access deny !Safe_ports
# Запретить CONNECT к небезопасным SSL портам
http_access deny CONNECT !SSL_ports
# Разрешить cachemgr доступ только с локального хоста
http_access allow localhost manager
http_access deny manager
# Разрешаем доступ с localhost
http_access allow localhost
#разрешаем доступ на основании доменных групп
http_access allow allowed-http-always
http_access allow SQUID-INTERNET-FULL_ACCESS
http_access allow SQUID-INTERNET-EXTENDED allowed-http-extended
http_access allow SQUID-INTERNET-EXTENDED !blocked-http
http_access allow SQUID-INTERNET-STANDART !blocked-http
#разрешаем доступ для mac устройств и http трафика
http_access allow allowed-mac-full-access
http_access allow allowed-mac-extended allowed-http-extended
http_access allow allowed-mac-extended !blocked-http
http_access allow allowed-mac !blocked-http
# Запрещаем все, что не разрешено
http_access deny all
#разрешаем доступ для mac устройств и https трафика
ssl_bump peek step1
ssl_bump bump allowed-mac-full-access monitored-HTTPS
ssl_bump bump allowed-mac-extended monitored-HTTPS
ssl_bump bump allowed-mac monitored-HTTPS
ssl_bump splice allowed-https-always
ssl_bump splice allowed-mac-full-access
ssl_bump splice allowed-mac-extended allowed-https-extended
ssl_bump splice allowed-mac-extended !blocked-https
ssl_bump splice allowed-mac !blocked-https
#запрещаем все https, что не разрешено
ssl_bump terminate all
# Интерфейсы и порты на которых будет слушать Squid
http_port 192.168.0.133:3128
http_port 192.168.0.133:3129 intercept
https_port 192.168.0.133:3127 intercept ssl-bump cert=/etc/squid/ssl_cert/myCA.pem generate-host-certificates=on dynamic_cert_mem_cache_size=4MB
# Настройки DNS. Без них может медленно работать
dns_nameservers 192.168.1.2 192.168.0.18
dns_v4_first on
#генерация динамических сертификатов
sslcrtd_program /usr/lib64/squid/security_file_certgen -s /etc/squid/ssl_db -M 4MB
# Настройки кеша
cache_dir ufs /var/spool/squid 100 16 256
coredump_dir /var/spool/squid
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
Перегружаем Squid:
# systemctl restart squid
Дополнительно
Для просмотра статистики написано большое количество различного софта log-analysis.
Наиболее известные SARG, ScreenSquid, lightsquid, SquidAnalyzer.
Для конфигурации выше пришлось использовать самописный анализатор логов, чтобы в отчет попадали полные имена пользователей, а не логины и MAC адреса. Кто знает perl и php может переделать ScreenSquid под свои нужды. У меня python периодически парсит access.log, закидывает результат в mysql, и по запросу выгружает статистику в html документ. Но это уже отдельная тема для разговора.
Также для проверки наличия сайта в файлах со списками url использую простенький скрипт python 3 (по желанию можно такой же сделать для определения MAC адреса в файлах):
import re
allowed_http_extended = '/etc/squid/allowed-http-extended.txt'
allowed_https_extended = '/etc/squid/allowed-https-extended.txt'
blocked_http = '/etc/squid/blocked-http.txt'
blocked_https = '/etc/squid/blocked-https.txt'
monitored_HTTPS = '/etc/squid/monitored-HTTPS.txt'
dict_blocked_http = {}
with open(blocked_http,'r',encoding="utf-8") as f:
for i, l in enumerate(f,start=1):
if l.strip() != '':
dict_blocked_http[i] = l.lower()
dict_blocked_https = {}
with open(blocked_https,'r',encoding="utf-8") as f:
for i, l in enumerate(f,start=1):
if l.strip() != '':
dict_blocked_https[i] = l.lower()
dict_allowed_http_extended = {}
with open(allowed_http_extended,'r',encoding="utf-8") as f:
for i, l in enumerate(f,start=1):
if l.strip() != '':
dict_allowed_http_extended[i] = l.lower()
dict_allowed_https_extended = {}
with open(allowed_https_extended,'r',encoding="utf-8") as f:
for i, l in enumerate(f,start=1):
if l.strip() != '':
dict_allowed_https_extended[i] = l.lower()
dict_monitored_HTTPS = {}
with open(monitored_HTTPS,'r',encoding="utf-8") as f:
for i, l in enumerate(f,start=1):
if l.strip() != '':
dict_monitored_HTTPS[i] = l.lower()
checked_site = input("Введите ссылку: ")
checked_site = checked_site.lower().strip()
for i in dict_blocked_http:
dict_key = dict_blocked_http.get(i).strip()
result = re.search(dict_key,checked_site)
if result != None:
print ("Совпадение в файле 'blocked-http.txt', строка '" + str(i) + "' регулярное выражение '" + dict_key + "'")
for i in dict_blocked_https:
dict_key = dict_blocked_https.get(i).strip()
result = re.search(dict_key,checked_site)
if result != None:
print ("Совпадение в файле 'blocked-https.txt', строка '" + str(i) + "' регулярное выражение '" + dict_key + "'")
for i in dict_allowed_http_extended:
dict_key = dict_allowed_http_extended.get(i).strip()
result = re.search(dict_key,checked_site)
if result != None:
print ("Совпадение в файле 'allowed_http_extended.txt', строка '" + str(i) + "' регулярное выражение '" + dict_key + "'")
for i in dict_allowed_https_extended:
dict_key = dict_allowed_https_extended.get(i).strip()
result = re.search(dict_key,checked_site)
if result != None:
print ("Совпадение в файле 'allowed_https_extended.txt', строка '" + str(i) + "' регулярное выражение '" + dict_key + "'")
for i in dict_monitored_HTTPS:
dict_key = dict_monitored_HTTPS.get(i).strip()
result = re.search(dict_key,checked_site)
if result != None:
print ("Совпадение в файле 'monitored_HTTPS.txt', строка '" + str(i) + "' регулярное выражение '" + dict_key + "'")
Запускаем скрипт, вводим url ссылку, получаем список файлов с указанием номеров строк, с которыми нашлось совпадение.
На этом все.