Полная предаутентификация для Exchange с помощью Netscaler

от автора

Однажды в службе информационной безопасности решили, что не только лишь все должны иметь доступ к электронной почте снаружи периметра. Начали искать способы и поняли, что нам нужен продукт класса ADC. Решили попробовать реализовать с помощью имеющего у нас Citrix Netscaler, который берёт на себя функцию аутентификации и проверят, можно ли данному сотруднику разрешить доступ в почтовую систему. Получилось. Не зря система такая дорогая. Будет длинная статья-инструкция.

Статей на тему того, как подружить Microsoft Excnage Server и Cirtix Netscaler не то, чтобы на каждом углу, но найти можно. Все найденные статьи не закрывали поставленную задачу. В основном статьи заканчивались на переключателе контента (переключатель контента можно реализовать на HAProxy). Некоторые статьи описывали перехват веб-формы. Нам же необходимо было запретить доступ на основе членства в группе Active Directory. Получается, что мы сами себе придумали, что мы хотим совместить аутентификацию и авторизацию в одном флаконе и на одном экране логина.

Виртуальные каталоги Exchange для веб-почты используют стандартную аутентификацию (не на основе форм). Т.е. и для внутренних и для внешних подключений используются одни и те же почтовые сервера.

Как-то так получилось, что я «осторожно, сертифицированный специалист» и по одному и по другому продукту. В общем, списывать было не у кого, пришлось делать домашку самому.

Давайте сразу договоримся, что далее в тексте будем использовать 198.51.100.0/24 для внешних (белых) сетей, 192.168.0.0/16 для внутренних сетей. Пространство имён example.com для имён, доступных из сети интернет и examle.local для именования внутренних серверов.

Принцип работы такой:

Content Switch принимает соединение и передаёт его соответствующему виртуальному серверу. Виртуальный сервер производит аутентификацию. Проверка членства в группе производится с помощью механизма многофакторной аутентификации. Второй фактор не требует участия пользователя и происходит фоном. Если проверка пройдена, то пускаем, если нет — показываем пользователю сообщение, что ему в доступе отказано.

Попутно защищаем пользователя от перебора пароля. Если честно, то именно защита от перебора пароля была для ИТ основной задачей, поскольку именно к ИТ приходят пользователи, которые сменили пароль и забыли поменять его на телефоне, тем самым вызывая блокировку учётной записи.

Схему взаимосвязи сущностей Netscaler постарался отразить на изображении ниже. Какие-то детали мог упустить

Пойдём уже настраивать Netscaler. Будем делать это поэтапно. Пояснения будут по ходу.

Пояснения

Citrix Netscaler с версии 13 называется Citrix ADC

Стоит отметить, что для Exchnage 2013 необходимо опубликовать и OWA и ECP, а для Exchange 2016/2019 только OWA

Если у вас гибрид и Teams, то нельзя делать предаутентификацию на EWS (перестанет работать календарь в Teams)

В нашем примере сервера Exchange именуются exch-server-nn и находятся в сети 192.168.9.0/24. Если у вас Exchange 2013, то exch-server-nn — это сервера с ролью ClientAccess. Внутренний домен EXAMPLE.LOCAL, внешнее имя mail.example.com

1 Основные настройки

Создадим базовые сущности, необходимые для работы, а именно сервера, сервис-группы, мониторы, переключатель контента

#Create Server add server exch-server-01 192.168.9.1 add server exch-server-02 192.168.9.2  #Create Service Groups add serviceGroup svcgrp_ex2019pub_owa SSL -cip ENABLED X-Forwarded-For add serviceGroup svcgrp_ex2019pub_async SSL -cip ENABLED X-Forwarded-For add serviceGroup svcgrp_ex2019pub_rpc SSL -cip ENABLED X-Forwarded-For add serviceGroup svcgrp_ex2019pub_ews SSL -cip ENABLED X-Forwarded-For add serviceGroup svcgrp_ex2019pub_autodisover SSL -cip ENABLED X-Forwarded-For add serviceGroup svcgrp_ex2019pub_oab SSL -cip ENABLED X-Forwarded-For add serviceGroup svcgrp_ex2019pub_mapi SSL -cip ENABLED X-Forwarded-For add serviceGroup svcgrp_ex2019pub_ecp SSL -cip ENABLED X-Forwarded-For  #Create monitors add lb monitor mon_exch_owa HTTP-ECV -send "GET /owa/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES add lb monitor mon_exch_async HTTP-ECV -send "GET /Microsoft-Server-ActiveSync/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES add lb monitor mon_exch_rpc HTTP-ECV -send "GET /rpc/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES add lb monitor mon_exch_ews HTTP-ECV -send "GET /ews/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES add lb monitor mon_exch_autodiscover HTTP-ECV -send "GET /Autodiscover/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES add lb monitor mon_exch_oab HTTP-ECV -send "GET /oab/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES add lb monitor mon_exch_mapi HTTP-ECV -send "GET /mapi/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES add lb monitor mon_exch_ecp HTTP-ECV -send "GET /ecp/healthcheck.htm" recv 200 -LRTM DISABLED -secure YES

Соединяем одно с другим, а именно линкуем сервера и мониторы к группам

#Bind Service Groups #Replace FQDN and ip address regarding your environment bind servicegroup svcgrp_ex2019pub_owa exch-server-01 443 bind servicegroup svcgrp_ex2019pub_owa exch-server-02 443 bind serviceGroup svcgrp_ex2019pub_owa -monitorName mon_mail_owa bind servicegroup svcgrp_ex2019pub_async exch-server-01 443 bind servicegroup svcgrp_ex2019pub_async exch-server-02 443 bind servicegroup svcgrp_ex2019pub_async -monitorName mon_mail_async bind servicegroup svcgrp_ex2019pub_rpc exch-server-01 443 bind servicegroup svcgrp_ex2019pub_rpc exch-server-02 443 bind servicegroup svcgrp_ex2019pub_rpc -monitorName mon_mail_rpc bind servicegroup svcgrp_ex2019pub_ews exch-server-01 443 bind servicegroup svcgrp_ex2019pub_ews exch-server-02 443 bind servicegroup svcgrp_ex2019pub_ews -monitorName mon_mail_ews bind servicegroup svcgrp_ex2019pub_autodisover exch-server-01 443 bind servicegroup svcgrp_ex2019pub_autodisover exch-server-02 443 bind servicegroup svcgrp_ex2019pub_autodisover -monitorName mon_mail_autodiscover bind servicegroup svcgrp_ex2019pub_oab exch-server-01 443 bind servicegroup svcgrp_ex2019pub_oab exch-server-02 443 bind servicegroup svcgrp_ex2019pub_oab -monitorName mon_mail_oab bind servicegroup svcgrp_ex2019pub_mapi exch-server-01 443 bind servicegroup svcgrp_ex2019pub_mapi exch-server-02 443 bind servicegroup svcgrp_ex2019pub_mapi -monitorName mon_mail_mapi bind servicegroup svcgrp_ex2019pub_ecp exch-server-01 443 bind servicegroup svcgrp_ex2019pub_ecp exch-server-02 443 bind servicegroup svcgrp_ex2019pub_ecp -monitorName mon_mail_ecp

Создадим виртуальные сервера и прилинкуем к ним соответствующие сервисные группы

#Create Load Balancer add lb vserver lb_vs_ex2019pub_owa SSL 0.0.0.0 0 -persistenceType NONE add lb vserver lb_vs_ex2019pub_async SSL 0.0.0.0 0 -persistenceType SRCIPDESTIP add lb vserver lb_vs_ex2019pub_rpc SSL 0.0.0.0 0 -persistenceType SOURCEIP -timeout 30 add lb vserver lb_vs_ex2019pub_ews SSL 0.0.0.0 0 -persistenceType NONE add lb vserver lb_vs_ex2019pub_autodiscover SSL 0.0.0.0 0 -persistenceType NONE -timeout 30 add lb vserver lb_vs_ex2019pub_oab SSL 0.0.0.0 0 -persistenceType NONE add lb vserver lb_vs_ex2019pub_mapi SSL 0.0.0.0 0 -persistenceType SOURCEIP -timeout 30 add lb vserver lb_vs_ex2019pub_ecp SSL 0.0.0.0 0 -persistenceType NONE  #Bind Service Groups to vServer bind lb vserver lb_vs_ex2019pub_owa svcgrp_ex2019pub_owa bind lb vserver lb_vs_ex2019pub_async svcgrp_ex2019pub_async bind lb vserver lb_vs_ex2019pub_rpc svcgrp_ex2019pub_rpc bind lb vserver lb_vs_ex2019pub_ews svcgrp_ex2019pub_ews bind lb vserver lb_vs_ex2019pub_autodiscover svcgrp_ex2019pub_autodisover bind lb vserver lb_vs_ex2019pub_oab svcgrp_ex2019pub_oab bind lb vserver lb_vs_ex2019pub_mapi svcgrp_ex2019pub_mapi bind lb vserver lb_vs_ex2019pub_ecp svcgrp_ex2019pub_ecp  #Bind SSL certificate #Replace certificate name bind ssl vserver lb_vs_ex2019pub_owa -certkeyName 'mail.example.com' bind ssl vserver lb_vs_ex2019pub_async -certkeyName 'mail.example.com' bind ssl vserver lb_vs_ex2019pub_rpc -certkeyName 'mail.example.com' bind ssl vserver lb_vs_ex2019pub_ews -certkeyName 'mail.example.com' bind ssl vserver lb_vs_ex2019pub_autodiscover -certkeyName 'mail.example.com' bind ssl vserver lb_vs_ex2019pub_oab -certkeyName 'mail.example.com' bind ssl vserver lb_vs_ex2019pub_mapi -certkeyName 'mail.example.com' bind ssl vserver lb_vs_ex2019pub_ecp -certkeyName 'mail.example.com'

Переходим к чуть более интересному — переключатель контента. Создадим политики на основании URL и прилинкуем соответствующие политики к соответствующим виртуальным серверам. Адрес 198.51.100.100 — это белый адрес, доступный из сети интернет (на всякий случай отмечу, что сеть 198.51.100.0/24 используется в примерах в документации и запрещена к маршрутизации) В качестве действия по умолчанию будет веб-почта.

#Create Content Switch #Replace IP address of Content Switch add cs vserver cs_ex2019pub_http HTTP 198.51.100.100 80 add cs vserver cs_ex2019pub_ssl SSL 198.51.100.100 443  #Replace certificate name bind ssl vserver cs_ex2019pub_ssl -certkeyName 'mail.example.com'  #Create Content Switch Policies add cs action cs_act_ex2019pub_owa -targetLBVserver lb_vs_ex2019pub_owa add cs policy cs_pol_ex2019pub_owa -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/owa")' -action cs_act_ex2019pub_owa add cs action cs_act_ex2019pub_ews -targetLBVserver lb_vs_ex2019pub_ews add cs policy cs_pol_ex2019pub_ews -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/ews")' -action cs_act_ex2019pub_ews add cs action cs_act_ex2019pub_autodiscover -targetLBVserver lb_vs_ex2019pub_autodiscover add cs policy cs_pol_ex2019pub_autodiscover -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/autodiscover")' -action cs_act_ex2019pub_autodiscover add cs action cs_act_ex2019pub_async -targetLBVserver lb_vs_ex2019pub_async add cs policy cs_pol_ex2019pub_async -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/Microsoft-Server-ActiveSync")' -action cs_act_ex2019pub_async add cs action cs_act_ex2019pub_oab -targetLBVserver lb_vs_ex2019pub_oab add cs policy cs_pol_ex2019pub_oab -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/oab")' -action cs_act_ex2019pub_oab add cs action cs_act_ex2019pub_mapi -targetLBVserver lb_vs_ex2019pub_mapi add cs policy cs_pol_ex2019pub_mapi -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/mapi")' -action cs_act_ex2019pub_mapi add cs action cs_act_ex2019pub_rpc -targetLBVserver lb_vs_ex2019pub_rpc add cs policy cs_pol_ex2019pub_rpc -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/rpc")' -action cs_act_ex2019pub_rpc add cs action cs_act_ex2019pub_ecp -targetLBVserver lb_vs_ex2019pub_ecp add cs policy cs_pol_ex2019pub_ecp -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/ecp")' -action cs_act_ex2019pub_ecp add cs policy cs_pol_ex2019pub_cgi -rule 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/cgi")' -action cs_act_ex2019pub_owa   #Bind Content Switch Policies bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_owa -priority 110 bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_ews -priority 120 bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_autodiscover -priority 130 bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_async -priority 140 bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_oab -priority 150 bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_mapi -priority 160 bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_rpc -priority 170 bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_ecp -priority 180 bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_cgi -priority 190  #default action bind cs vserver cs_ex2019pub_ssl -lbvserver lb_vs_ex2019pub_owa

Для 80 порта команды не сохранились, поскольку делались из веб-интерфейса. Суть заключается в том, что создаётся ответчик resp_act_redirect_http_https_all, который перенаправляет на тот же самый url меняя http на https. Создан виртуальный сервер lb_vs_redirect_http_https_all, к которому прилинкована политика этого ответчика. Должно быть примерно так:

#Replace http to https add responder action resp_act_redirect_http_https_all redirect '"https://"+HTTP.REQ.HOSTNAME+"/"' add responder policy resp_pol_redirect_http_https_all 'true' resp_act_owa  #default action bind cs vserver cs_ex2019pub_http -lbvserver lb_vs_redirect_http_https_all

очень важно сохранить конфигурацию 🙂

save ns config

В общем-то, в данном виде система уже может быть использована. Хотя на сейчас она представляет собой обычный обратный прокси. Хорошо, продолжим усложнять и накручивать.

2 Сервер аутентификации и авторизации, политика ldap

svc_read_netscaler@example.local — сервисная учётная запись в домене с правами чтения домена (достаточно группы Domain Users)

192.168.3.11 — VIP адрес балансировщика LDAP, за которым отвечают несколько котроллеров домена (в простом случае адрес контроллера домена)

«&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(proxyAddresses=*)» — LDAP фильтр, который выдаёт включенные учётные записи пользователей, имеющих почту на Exchange

maaa.examle.com — это адрес с веб-формой, на который происходит перенаправление для проверки логина/пароля. Это тоже сущность Netscaler, может выступать в роли SSO в пределах Netscaler.

Создадим LDAP сервера и политики к этим серверам. С проверкой по sAMAccountName и с проверкой по UserPrincipalName. При этом два сервера с отключенной аутентификацией понадобятся на следующем этапе.

# Create LDAP servers add ldapAction auth_srv_ldap_ex2019pub_SAM -serverIP "192.168.3.11" -serverPort "389" -secType "TLS" -svrType "AD" -authTimeout 3 -ldapBindDn "svc_read_netscaler@example.local" -ldapBase "DC=example,DC=local" -authentication enabled -ldapLoginName "sAMAccountName" -passwdChange ENABLED - searchFilter "&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(proxyAddresses=*)" -groupAttrName "memberOf" - subAttributeName "cn" -ssoNameAttribute "userPrincipalName" -email "mail" -requireUser YES -validateServerCert NO -nestedGroupExtraction OFF -followReferrals ON - maxLDAPReferrals 1 -referralDNSLookup A-REC -nestedGroupExtraction ON -maxNestingLevel 2 -groupNameIdentifier "sAMAccountName" -groupSearchAttribute "memberOf" - groupSearchSubAttribute "cn" -ldapbindDnPassword  add ldapAction auth_srv_ldap_ex2019pub_UPN -serverIP "192.168.3.11" -serverPort "389" -secType "TLS" -svrType "AD" -authTimeout 3 -ldapBindDn "svc_read_netscaler@example.local" -ldapBase "DC=example,DC=local" -authentication enabled -ldapLoginName "userPrincipalName" -passwdChange ENABLED - searchFilter "&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(proxyAddresses=*)" -groupAttrName "memberOf" - subAttributeName "cn" -ssoNameAttribute "userPrincipalName" -email "mail" -requireUser YES -validateServerCert NO -nestedGroupExtraction OFF -followReferrals ON - maxLDAPReferrals 1 -referralDNSLookup A-REC -nestedGroupExtraction ON -maxNestingLevel 2 -groupNameIdentifier "sAMAccountName" -groupSearchAttribute "memberOf" - groupSearchSubAttribute "cn" -ldapbindDnPassword  add ldapAction auth_srv_ldap_ex2019pub_SAM_noAuth -serverIP "192.168.3.11" -serverPort "389" -secType "TLS" -svrType "AD" -authTimeout 3 -ldapBindDn "svc_read_netscaler@example.local" -ldapBase "DC=example,DC=local" -authentication DISABLED -ldapLoginName "sAMAccountName" -passwdChange DISABLED - searchFilter "&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(proxyAddresses=*)" -groupAttrName "memberOf" - subAttributeName "cn" -ssoNameAttribute "userPrincipalName" -email "mail" -requireUser YES -validateServerCert NO -nestedGroupExtraction OFF -followReferrals ON - maxLDAPReferrals 1 -referralDNSLookup A-REC -nestedGroupExtraction ON -maxNestingLevel 2 -groupNameIdentifier "sAMAccountName" -groupSearchAttribute "memberOf" - groupSearchSubAttribute "cn" -ldapbindDnPassword  add ldapAction auth_srv_ldap_ex2019pub_UPN_noAuth -serverIP "192.168.3.11" -serverPort "389" -secType "TLS" -svrType "AD" -authTimeout 3 -ldapBindDn "svc_read_netscaler@example.local" -ldapBase "DC=example,DC=local" -authentication DISABLED -ldapLoginName "userPrincipalName" -passwdChange DISABLED -searchFilter "&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(proxyAddresses=*)" -groupAttrName "memberOf" - subAttributeName "cn" -ssoNameAttribute "userPrincipalName" -email "mail" -requireUser YES -validateServerCert NO -nestedGroupExtraction OFF -followReferrals ON - maxLDAPReferrals 1 -referralDNSLookup A-REC -nestedGroupExtraction ON -maxNestingLevel 2 -groupNameIdentifier "sAMAccountName" -groupSearchAttribute "memberOf" - groupSearchSubAttribute "cn" -ldapbindDnPassword   #Create LDAP advanced policy add authentication policy advauth_pol_ldap_ex2019pub_SAM -rule true -action auth_srv_ldap_ex2019pub_SAM add authentication policy advauth_pol_ldap_ex2019pub_UPN -rule true -action auth_srv_ldap_ex2019pub_UPN add authentication policy advauth_pol_ldap_ex2019pub_SAM_noAuth -rule true -action auth_srv_ldap_ex2019pub_SAM_noAuth add authentication policy advauth_pol_ldap_ex2019pub_UPN_noAuth -rule true -action auth_srv_ldap_ex2019pub_UPN_noAuth 

Теперь создадим AAA сервер и привяжем к нему две из вышесозданных политик. Как раз этот AAA сервер занимается защитой от перебора пароля — это у AAA штатный функционал

#Create AAA VServer add authentication vserver aaa_vs_ex2019pub_ldap SSL 0.0.0.0 -maxLoginAttempts 3 -failedLoginTimeout 5 bind ssl vserver aaa_vs_ex2019pub_ldap -certkeyName 'mail.example.com' bind authentication vserver aaa_vs_ex2019pub_ldap -portaltheme StoreFrontLogOnTheme   #Bind LDAP Policies to AAA vserver bind authentication vserver aaa_vs_ex2019pub_ldap -policy advauth_pol_ldap_ex2019pub_SAM -priority 200 -gotoPriorityExpression NEXT bind authentication vserver aaa_vs_ex2019pub_ldap -policy advauth_pol_ldap_ex2019pub_UPN -priority 210 -gotoPriorityExpression NEXT

Сервера созданы. Теперь определим политики сессий и прилинкуем их к AAA серверу

#Create AAA Session Policy add tm sessionAction tm_act_ex2019pub_owa_sso -defaultAuthorization ALLOW -SSO ON -ssoDomain 'examle.local'  #add tm sessionPolicy tm_pol_ex2019pub_owa_sso_v2 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/owa/auth/logon.aspx")' tm_act_ex2019pub_owa_sso add tm sessionPolicy tm_pol_ex2019pub_owa_sso 'ns_true' tm_act_ex2019pub_owa_sso  #Create SSO Form and Policies add tm formSSOAction sso_profile_ex2019pub_owa -actionURL "/owa/auth.owa" -userField "username" -passwdField "password" -responsesize "60000" -ssoSuccessRule 'HTTP.RES.SET_COOKIE.COOKIE("cadata").VALUE("cadata").LENGTH.GT(70)' -nvtype DYNAMIC -submitMethod POST add tm trafficAction traffic_prof_ex2019pub_owa -SSO ON -appTimeout 1 -formSSOAction sso_profile_ex2019pub_owa add tm trafficAction traffic_prof_ex2019pub_owa_logout -InitiateLogout ON   add tm trafficPolicy traffic_pol_ex2019pub_owa 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/owa/auth/logon.aspx")' traffic_prof_ex2019pub_owa add tm trafficPolicy traffic_pol_ex2019pub_owa_logout 'HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS("/owa/logoff.owa")' traffic_prof_ex2019pub_owa_logout  #Bind Traffic Session Policy to the AAA vServer bind authentication vserver aaa_vs_ex2019pub_ldap -policy tm_pol_ex2019pub_owa_sso -priority 100 -gotoPriorityExpression NEXT 

Далее необходимо добавить правило в переключатель контента, созданный а первой части, чтобы переключатель понимал, как поступать с запросами, идущими на maaa.examle.com

#Content Switch for AAA #Replace AuthenticationHost FQDN add cs action cs_act_ex2019pub_maaa -targetVserver aaa_vs_ex2019pub_ldap add cs policy cs_pol_ex2019pub_maaa -rule 'HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).EQ("maaa.examle.com")' -action cs_act_ex2019pub_maaa bind cs vserver cs_ex2019pub_ssl -policyName cs_pol_ex2019pub_maaa -priority 90

Осталось лёгким движением руки превратить брюки в шорты, а если это не получилось, то привязать созданный AAA сервер к ранее созданным (в первой части) виртуальным серверам. К веб почте и панели управления привязываем веб форму аутентификации, к остальным протоколам basic аутентификацию.

Снова отмечу, что в Exchange 2016/2019 не следует выпускать наружу ECP.

#Bind SSO Policies to the OWA vServer bind lb vserver lb_vs_ex2019pub_owa -policyName traffic_pol_ex2019pub_owa -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vserver lb_vs_ex2019pub_owa -policyName traffic_pol_ex2019pub_owa_logout -priority 110 -gotoPriorityExpression END -type REQUEST  #Set FBA and 401 authentication #Replace AuthenticationHost FQDN set lb vserver lb_vs_ex2019pub_owa -Authentication ON -authnVsName aaa_vs_ex2019pub_ldap -AuthenticationHost maaa.examle.com set lb vserver lb_vs_ex2019pub_ecp -Authentication ON -authnVsName aaa_vs_ex2019pub_ldap -AuthenticationHost maaa.examle.com set lb vserver lb_vs_ex2019pub_async -authn401 ON -authnVsName aaa_vs_ex2019pub_ldap set lb vserver lb_vs_ex2019pub_rpc -authn401 ON -authnVsName aaa_vs_ex2019pub_ldap set lb vserver lb_vs_ex2019pub_ews -authn401 ON -authnVsName aaa_vs_ex2019pub_ldap set lb vserver lb_vs_ex2019pub_oab -authn401 ON -authnVsName aaa_vs_ex2019pub_ldap set lb vserver lb_vs_ex2019pub_mapi -authn401 ON -authnVsName aaa_vs_ex2019pub_ldap set lb vserver lb_vs_ex2019pub_autodiscover -authn401 ON -authnVsName aaa_vs_ex2019pub_ldap

ну и конечно же сохраняемся save ns config, зря что ли в детстве в Doom играли.

Прекрасно! Настроен перехват аутентификации веб формой и basic. Но и эта реализация требует дальнейшей доработки, поскольку basic нас не устраивает, мы же возомнили себе, что мы специалисты и нам надо всё делать правильно. Поэтому продолжаем усложнять.

3 Negotiate

Кириллические логины НЕ работают, только латиница. Реализуем перехват аутентификации по NTLM, который необходим для того, чтобы в дальнейшем настроить авторизацию. Для этого использовал функционал двухфакторной аутентификации. Второй фактор скрыт от пользователя и представляет из себя извлечение групп на учётной записи. Применён на сервисы RPC, OAB, EWS, MAPI, AutoDiscover

svc_masa19 — учётная запись в домене с правами ограниченного делегирования.

https://mail.example.local/mapi/ — ресурс, по которому доступен почтовый сервер. (В данной статье не описано, но суть в том, что имя mail.example.local живёт на балансировщике и за этим именем отвечает несколько серверов)

Приступим. Создадим в Active Directory учётную запись svc_masa19 (для любопытных это расшифровывается как mail alternate service account)

На Nеtscaler создадим KCD аккаунт и политику к нему. Здесь в примере будет способ заведения учётной записи по паролю, хотя в приличных обществах такие учётные записи принято передавать в стороннюю систему с помощью keytab файла, что вполне себе поддерживает Netscaler.

# Create kerberos account and session policy for SSO add aaa kcdAccount kcd_acc_svc_masa19 -realmStr EXAMPLE.LOCAL -delegatedUser svc_masa19 -kcdPassword  add tm sessionAction tm_act_ex2019pub_kcd -defaultAuthorization ALLOW -SSO ON -ssoDomain 'EXAMPLE.LOCAL' -sessTimeout 10 -ssoCredential PRIMARY -httpOnlyCookie NO -kcdAccount kcd_acc_svc_masa19 add tm sessionPolicy tm_pol_ex2019pub_kcd 'ns_true' tm_act_ex2019pub_kcd

Дальше будет немного магии. Для начала создадим действие и политику согласования. Затем создадим схему схему логина и метки к ней. Прилинкуем к меткам LDAP без проверки подлинности, созданные на втором этапе. Это нужно для того, чтобы получить список групп на учётной записи.

После чего создадим ещё один AAA сервер, к которому прилинкуем проверку подлинности по согласованию и укажем, что в качестве второго фактора использовать созданную только что метку.

# Add Negotiate authentication advanced policy and action add negotiateAction neg_srv_ex2019pub_svc_masa19 -domain EXAMPLE.LOCAL -domainUser svc_masa19 -NTLMPath "https://mail.example.local/mapi/" - domainUserPasswd add authentication policy advauth_pol_neg_ex2019pub_svc_masa19 -rule true -action neg_srv_ex2019pub_svc_masa19  # Create login schema and policy label add authentication loginSchema login_ex2019pub_ldap -authenticationSchema noschema add authentication policyLabel pol_lab_ex2019pub_ldap -loginSchema login_ex2019pub_ldap  #Bind LDAP policy to policy label bind authentication policylabel pol_lab_ex2019pub_ldap -policyName advauth_pol_ldap_ex2019pub_SAM_noAuth -priority 200 -gotoPriorityExpression NEXT bind authentication policylabel pol_lab_ex2019pub_ldap -policyName advauth_pol_ldap_ex2019pub_UPN_noAuth -priority 210 -gotoPriorityExpression NEXT  # Create a new AAA vserver that uses KCD and bind the cert add authentication vserver aaa_vs_ex2019pub_negotiate_2fa SSL 0.0.0.0 -maxLoginAttempts 3 -failedLoginTimeout 5 bind ssl vserver aaa_vs_ex2019pub_negotiate_2fa -certkeyName 'mail.example.com'  # bind the negotiate and SSO policies to the new AAA Server bind authentication vserver aaa_vs_ex2019pub_negotiate_2fa -policy tm_pol_ex2019pub_kcd -priority 100 bind authentication vserver aaa_vs_ex2019pub_negotiate_2fa -policy advauth_pol_neg_ex2019pub_svc_masa19 -priority 100 -gotoPriorityExpression NEXT -nextFactor pol_lab_ex2019pub_ldap

Остаётся прилинковать одно к другому, а именно AAA сервер аутентификации по согласованию прилинковать к виртуальным серверам RPC, MAPI, OAB, EWS, Autodiscover

# bind the new AAA Server to the Load balancers that need KCD set lb vserver lb_vs_ex2019pub_mapi -authnVsName aaa_vs_ex2019pub_negotiate_2fa set lb vserver lb_vs_ex2019pub_rpc -authnVsName aaa_vs_ex2019pub_negotiate_2fa set lb vserver lb_vs_ex2019pub_ews -authnVsName aaa_vs_ex2019pub_negotiate_2fa set lb vserver lb_vs_ex2019pub_oab -authnVsName aaa_vs_ex2019pub_negotiate_2fa set lb vserver lb_vs_ex2019pub_autodiscover -authnVsName aaa_vs_ex2019pub_negotiate_2fa

помним про save ns config

Для учётной записи svc_masa19 необходимо произвести настройки. Добавить делегирование

На Exchange серверах необходимо разрешить аутентификацию согласованием

Get-OutlookAnywhere -server exch-server-01 | Set-OutlookAnywhere -IISAuthenticationMethods Negotiate,Ntlm,Basic

Казалось бы всё, задача решена. Если вдруг кто-то дочитал до этого места и всё ещё внимателен, то заметил, что до сих пор не решена задача от службы безопасности, а именно, пускать кого можно и не пускать, кого нельзя. Поэтому

4 Авторизация

В Active Directory есть группа deny_mail.example.com_access, членам которой запрещено подключаться к почте из вне.

Создадим политику авторизации и прилинкуем её ко всем виртуальным серверам, обслуживающим веб протоколы

#add and bind authorization policy add authorization policy pol_auth_mail.example.com_deny "AAA.USER.IS_MEMBER_OF(\"deny_mail.example.com_access\")" DENY  # authorization on base and negotiate vservers bind lb vs lb_vs_ex2019pub_async -policyName pol_auth_mail.example.com_deny -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vs lb_vs_ex2019pub_rpc -policyName pol_auth_mail.example.com_deny -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vs lb_vs_ex2019pub_ews -policyName pol_auth_mail.example.com_deny -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vs lb_vs_ex2019pub_oab -policyName pol_auth_mail.example.com_deny -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vs lb_vs_ex2019pub_mapi -policyName pol_auth_mail.example.com_deny -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vs lb_vs_ex2019pub_autodiscover -policyName pol_auth_mail.example.com_deny -priority 100 -gotoPriorityExpression END -type REQUEST

Добавим немного вежливости, уведомим пользователя, что ему отказано во входе. Для этого создадим простую html страничку

Перейти AppExpert\Responder\Responder HTML Pages
Вручную создать страницу mail.example.com_deny. Настаиваю не разгоняться с форматированием и обойтись текстом и тегами абзаца или обрыва строки.

После чего привяжем вывод этой страницы к соответствующим критериям

#add responder policy and action add responder action resp_act_ex2019pub_denypage respondwithhtmlpage mail.example.com_deny -responseStatusCode 200 -reasonPhrase '\"Access denied. Contact to your servicedesk.\"' add responder policy resp_pol_ex2019pub_denypage 'AAA.USER.IS_MEMBER_OF(\"deny_mail.example.com_access\") && HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).CONTAINS(\"/owa/logoff.owa\").NOT' resp_act_ex2019pub_denypage  #bind policy to vservers bind lb vs lb_vs_ex2019pub_owa -policyName resp_pol_ex2019pub_denypage -priority 100 -gotoPriorityExpression END -type REQUEST bind lb vs lb_vs_ex2019pub_ecp -policyName resp_pol_ex2019pub_denypage -priority 100 -gotoPriorityExpression END -type REQUEST

save ns config

Вот теперь действительно готово


Ссылки, которые навели на решение

Не самой простой для чтения, но наиболее полной мне кажется эта статья

https://citrixguyblog.com/2017/07/22/citrix-netscaler-loadbalancing-exchange-20132016-walkthrough-guide/

Ещё неплохие статьи для понимая процесса

https://github.com/slauger/netscaler_docs/blob/master/exchange2016.adoc
https://support.citrix.com/article/CTX222454 — How to Configure the NetScaler for Kerberos Constrained Delegation

И ещё куча документации на сайте Citrix и на https://www.carlstalhood.com/


ссылка на оригинал статьи https://habr.com/ru/post/693428/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *