Posts on this page:
На днях столкнулся с весьма интересным случаем:
На сервере Hyper-V работает виртуалка с ролью Enterprise CA и тут понадобилось перезагрузить физический хост. Всё прошло нормально, но утром посыпались жалобы, что люди не могут с токенами войти в систему и пользователи, подключающиеся к терминальному серверу по протоколу RDP-TLS получали одну и ту же ошибку: A revocation check could not be performed for the certificate. Начав расследование инцидента выяснилось, что CA по каким-то причинам отказался публиковать CRL'ы. Причём в эвентлоге ничего подозрительного обнаружено не было. Посмотрев последний CRL обнаружил, что время в Next Publish совпало с тем временем, когда хост Hyper-V ребутился (это было видно по эвентлогу загрузки системы). Как известно, по умолчанию Hyper-V при выключении сохраняет состояние виртуальных машин (как бы отправляет их в режим "sleep") и при включении обратно, восстанавливает их из этого режима. Вобщем, у CA был забит триггер обновления CRL'ов на определённое время и виртуалка его проспала. После этого CA даже не делал попыток переопубликовать CRL в течении 8 (или около того) часов, пока я их вручуню не опубликовал. 2-часовой overlap по очевидным причинам не спас ситуацию. Как выяснилось, CA не будет обновлять такие CRL'ы пока:
Пораскинув мозгами я проверил ещё один момент — работу Key Archival, т.к. сертификат CA Exchange обновляется по такому же приципу. Т.е. если физический хост временно недоступен (выключен, перезагружается, ковыряется в носу) и в этот период истекает сертификат CA Exchange, то после возвращения виртуалки из сна этот сертификат не обновляется и архивирование ключей перестаёт работать. Может, я один такой счастилвчик, кто нарвался на такую несложную, но противную проблему, но факт остаётся фактом. И здесь, CA не будет предпринимать попыток обновить CA Exchange пока:
Чтобы предотвратить подобное в дальнейшем, я выбрал следующий воркэраунд для Hyper-V:
Как видно из описания, вместе с выключением физического сервера, виртуальные машины с Enterprise CA будут выключаться тоже и включаться после включения физического сервера, что предотвратит состояния сна для Enterprise CA и подобная ситуация больше не должна проявляться.
Иногда при публикации нового CRL вы получаете вот такую интересную ошибку: The directory name is invalid. 0x8007010b (WIN32/HTTP:267):
Откуда и почему она взялась — никто не знает, т.к. «я ничего не делал, оно само сломалось!». Иногда это оказывается правдой, но чаще — нет, администратор что-то сделал и всё поломал. Эта ошибка означает только одно: CA не смог поместить файлы либо в локальную папку, сетевую папку или опубликовать в LDAP. Не существует универсального способа определить причину ошибки, но есть универсальная методология поиска проблемы. Во-первых нужно залогониться на сервер CA и выполнить там следующую команду:
certutil –getreg CA\CRLPublicationURLs
и выбирайте все пути, под которыми есть хоть один из указанных флагов:
по этим путям сервер CA публикует физические файлы. Если это локальный путь, убедитесь, что он существует и учётная запись System имеет право записи в неё. Если это сетевая папка, убедитесь, что:
Если любое из этих условий не выполняется — вы получите ошибку.
Если это путь LDAP, убедитесь в следующем:
Если это путь LDAP, убедитесь в следующем. Когда всё исправлено, можно пробовать повторно публиковать CRL'ы:
certutil –CRL
Примечание: иногда бывает просто опечатка при конфигурировании пути в оснастке CA или названии целевой папки. Поэтому обращайте внимание на правильность указанных путей.
Вот и всё. Надеюсь такая нехитрая методичка поможет вам бороться с такой назойливой ошибкой.
Частенько появляются вопросы про просмотр хранилищ сертификатов на удалённых компьютерах из PowerShell. Встроенный провайдер CERT:\ не умеет такого. Командлетов для этой задачи тоже нет (хотя PowerShell вообще не содержит ни одного даже самого примитивного командлета для работы с сертификатами). Как быть и что делать? Ведь MMC умеет ходить по хранилищам удалённых компьютеров. Ответ на самом деле простой до безобразия, но о нём почти ничего не написано.
Как известно для особой работы с хранилищем сертификата (в смысле не только посмотреть, что там есть, но и добавить туда ещё сертификатов) мы используем класс X509Store. Сначала мы создаём соответствующий объект хранилища требуемого контекста (тип хранилища и название контейнера) и методом Open() открываем его. Но в списке конструкторов класса X509Store нет ничего похожего, что бы указывало на возможность указания другого компьютера. Чаще всего используется вот этот: X509Store(String, StoreLocation). В качестве первого параметра как правило указываем название контейнера, а в качестве второго указываем само хранилище — CurrentUser или LocalMachine. Однако, для этого конструктора есть один трюк: если к первому аргументу приписать имя компьютера, мы получим доступ к хранилищу удалённого компьютера и вот как это выглядит:
# создаём объект класса X509Store с указанием удалённого компьютера в формате: # \\ИмяКомпьютера\НазваниеКонтейнера. Второй аргумент всегда должен быть LocalMachine. $store = New-Object Security.Cryptography.X509Certificates.X509Store(\\ComputerName\ContainerName, "LocalMachine") # открываем соответствующий контейнер в режиме ReadOnly. Если открываем для записи, тогда # флаг должен быть ReadWrite. $store.Open("ReadOnly") # просматриваем содержимое контейнера. $store.Certificates # вытворяем гадости с сертификатами удалённой машины
Примечание: второй аргумент в данном сценарии всегда должен быть LocalMachine, поскольку мы не имеем возможности подключаться к пользовательским хранилищам удалённых компьютеров.
Даже встроенным ремотингом PowerShell'а не нужно заморачиваться. С одной стороны это крутой чит — можно не отходя от кассы доставить сертификатов куда надо. Но тут есть один нюанс. Даже имея права стандартного пользователя можно получить такой доступ, если ремотинг .NET'а не зарезан фиреволом (что внутри периметра мало практикуется) и стащить компьютерный сертификат с закрытым ключом со всеми вытекающими последствиями. Правда, тут стоит оговориться, что стащить удастся только сертификат, у которого закрытый ключ помечен как Exportable. Но, учитывая массовые рекомендации вайтпеперов МСа, в подавляющем случае это будет так. Защититься от этого можно тремя способами (расположены в порядке возрастания стоимости решения):
Первый метод самый дешёвый и простой. Он не требует каких-то специальных знаний от администратора. Второй относительно дешёв, но требует достаточно глубоких знаний от администратора, т.к. некорректно настроенный фиревол может привести к потере удалённого контроля над сервером. А третий прост примерно как и первый способ, но требует определённых капиталовложений (порядка нескольких килобаксов за единицу девайса). Об этом можно дискутировать долго и упорно, моя же задача здесь предельно проста: рассказать как решить задачу и поведать о возможных последствиях :-)
Некоторое время я описал баг в AppLocker'е, который заключается в некорректной обработке правил пути, если путь содержит неанглийские буквы (подробнее см. Очередной баг в AppLocker). Как я уже говорил, я открыл кейс в саппорте и обещал отписаться, если будут какие-то новости. И я выполняю своё обещание публикацией официального ответа Microsoft:
We've investigated the issue and it appears to be a problem in the implementation of case-insensitive path comparison for characters outside the ASCII range. Fortunately it seems there is a workaround for the time being. If, in Local Security Policy, one specifies paths in all-uppercase characters, including uppercasing any non-ASCII characters as appropriate, then the rule will match properly. Concretely, for your example 'Mapīte', putting that string with lowercase ī in a rule's path in Local Security Policy will not work; however putting the string 'MAPĪTE' with uppercase Ī does seem to work.
Т.е. если путь содержит буквы верхней таблицы ASCII (символы 128 и выше), путь следует прописывать заглавными буквами. Я уже собрался наваять костыль на пошике, который будет делать это за меня (за счёт использования метода String.ToUpper()), но очень быстро обломался, поскольку консоль пошика не способна отображать диактрические знаки и скопировать правильный путь из консоли не удастся и всю работу по озаглавливанию букв придётся делать вручную.