Рекомендации по установке СУБД InterSystems Caché в продуктовом режиме

  • Tutorial
Эта статья была написана, как попытка поделиться опытом по установке СУБД InterSystems Caché в продуктовом режиме. Все знают, что конфигурация СУБД для разработки сильно отличается от боевых условий. Если разработка, как правило, ведется в тепличных условиях с минимальными настройками безопасности, то когда мы выкладываем свой проект в живой Интернет, то должны максимально озаботиться его надежным и бесперебойным существованием в агрессивной среде.

Порядок установки СУБД InterSystems Caché на повышенном уровне безопасности

Настройки безопасности ОС


Начать нужно с операционной системы, необходимо выполнить следующее:
  • Минимизировать права технологической учетной записи СУБД Caché
  • Переименовать учетную запись администратора локального компьютера.
  • Оставить в ОС только минимум необходимых пользователей.
  • Своевременно устанавливать обновления безопасности для ОС и используемых служб и сервисов.
  • Использовать и регулярно обновлять антивирусное программное обеспечение
  • Отключить или удалить неиспользуемые службы и сервисы.
  • Ограничить доступ к файлам базы данных
  • Ограничить права на файлы данных Caché (оставить только у владельца и администраторов БД)
  • Для UNIX/Linux систем требуется создать следующие типы групп и пользователей, которых необходимо создать до начала инсталляции:
    • Owner user ID
    • Management group ID
    • Internal Caché system group ID
    • Internal Caché user ID


Настройки безопасности InterSystems Caché времени установки


Производитель СУБД компания InterSystems настоятельно рекомендует разворачивать прикладные решения только на версиях не ниже Caché 2015.2.

При установке необходимо выполнить следующие действия:


  • Выбрать режим установки Locked down (Повышенные)
  • Выбрать режим установки Custom Setup и в нем выбрать только те компоненты, которые минимально необходимы для работы прикладного решения
  • При установке указать порт SuperServer, отличный от стандартного для установок TCP порта 1972
  • При установке указать порт внутреннего веб сервера, отличный от стандартного для установок TCP порта 57772
  • В качестве пути для размещения экземпляра Caché указать отличный от стандартного путь (для Windows систем путь по умолчанию C:\lnterSystems\Cache, для UNIX/Linux систем — /usr/Cachesys

Настройки безопасности Caché после установки


После установки должны быть выполнены следующие действия (большинство из них выполнено при режиме инсталляции Locked down (Повышенные):


Отключены все сервисы и ресурсы, которые не используются прикладными системами сертифицируемого решения.

Для сервисов, использующих сетевой доступ, должны быть явно заданы IP адреса, с которых возможно удаленное взаимодействие.

Должны быть отключены неиспользуемые CSP веб приложения.

Для необходимых CSP приложений должен быть исключен доступ к ним без аутентификации и авторизации.

Должен быть закрыт паролем и ограничен доступ к CSP Gateway.

Должен быть включен аудит работы СУБД.

Для файла конфигурации должна быть включена опция шифрования.

В качестве проверки безопасности настроек системы должен быть запущен с портала управления Security Advisor и выполнены рекомендации по результатам его работы.

[Home] -> [System] > [Security Management] > [Services]
Для сервисов (раздел Services):

Ability to set % globals should be turned off — Возможность изменения процентных глобалов должна быть выключена. Так как часто такие глобалы используются для работы системного кода, изменения таких переменных могут привести к непредсказуемым последствиям.

Unauthenticated should be off — Неаутентифицированный доступ должен быть выключен. Неаутентифицированный доступ к сервису предоставляет всем пользователям доступ к нему

Service should be disabled unless required — Если сервис не используется, он должен быть отключен. Доступ к любому сервису, который не используется прикладным решением может обеспечить неоправданный уровень доступа к системе

Service should use Kerberos authentication — Доступ через любой другой механизм аутентификации не обеспечивает максимальный уровень безопасности

Service should have client IP addresses assigned — IP адреса подключений к сервису должны быть заданы явно. Ограничение IP адресов, с которых соединения будут приняты, позволяют более жестко контролировать соединения к Caché

Service is Public — Public сервисы дают возможность всем пользователям, включая не требующую аутентификации учетную запись UnknownUser, получать нерегулируемый доступ к Caché

[Home] -> [System] > [Security Management] > [Web Applications]
Приложения (CSP, Privileged Routine, and Client Applications)



Application is Public — Public приложения дают возможность всем пользователям, включая не требующую аутентификации учетную запись UnknownUser, получать нерегулируемый доступ к Caché

Application conditionally grants the %AII role — Система не может считаться защищенной, если приложение потенциально имеет возможность делегировать своим пользователям все привилегии. Приложения не должны делегировать все привилегии

Application grants the %AII role — Приложение явно делегирует все привелегии своим пользователям. Приложения не должны делегировать все привилегии

1.Управление пользователями



1.1 Управление системными учетными записями



Необходимо убедиться, что заблокированы или удалены неиспользуемые системные учетные записи, а для используемых системных учетных записей изменен пароль.

Для определения таких учетных записей необходимо использовать компоненту портала управления Security Advisor. Для этого необходимо зайти в портал управления на [Home] > [Security Management] > [Security Advisor] и для записей в разделе Users, для которых Recommendations = «Password should be changed from default password», должна быть произведена смена паролей у соответствующих пользователей.



1.2 Управление привилегированными учетными записями



Если СУБД администрируют несколько человек, то для каждого должна быть создана персональная учетная запись, наделенная минимально необходимыми привилегиями для выполнения должностных обязанностей.

1.3 Управление правами и привилегиями



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

1.4 Разграничение прав доступа



Для проверки настроек безопасности в плане разграничения прав доступа, запустите Security Advisor. Необходимо выполнить следующие действия в зависимости от рекомендаций, выдаваемых Security Advisor.

Для ролей (Roles):



This role holds privileges on the Audit database — Эта роль имеет привилегии доступа к базе аудита. Доступ на чтение позволяет использовать данные аудита ненадлежащим образом. Доступ на запись позволяет скомпроментировать данные аудита

This role holds the %Admin_Secure privilege — Эта роль включает в себя роль %Admin_Secure, которая позволяет изменять привилегии доступа для других пользователей/

This role holds WRITE privilege on the CACHESYS database — Эта роль дает право на запись в системную базу CACHESYS, что позволяет изменить системный код и системные настройки Caché

Для пользователей (Users):



At least 2 and at most 5 users should have the %AII role — По крайней мере, 2 и не более 5 пользователи должны иметь роль %Аll. Слишком мало пользователей с такой ролью может привести к проблемам доступа в аварийных ситуациях; слишком много пользователей может нарушить общую безопасность системы.

This user holds the %AII role — Этот пользователь имеет роль %Аll. Необходимо проверить необходимость присвоения этой роли данному пользователю.

UnknownUser account should not have the %AII role — Система не может считаться безопасной, если UnknownUser обладает ролью %Аll.

Account has never been used — Учетная запись никогда не использовалась. Неиспользуемые учетные записи могут использоваться при попытке получить несанкционированный доступ.

Account appears dormant and should be disabled — Учетная запись неактивна и должна быть отключена. Неактивные учетные записи (те, которые не были использованы в течение 30 дней) могут использоваться при попытке получить несанкционированный доступ.

Password should be changed from default password — Значение по умолчанию для пароля должно быть изменено.

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

1.5 Настройка парольной политики



Поддержка чувствительности к регистру паролей включена в Caché по умолчанию.

Парольная политика реализуется через портал управления системой в разделе:
[Home]>[Security Management] > [System Security Settings] > [System-wide Security Parameters].

Настройка необходимой сложности паролей происходит с помощью указания шаблона для паролей в параметре Password Pattern. По умолчанию для установки с максимальной
безопасностью Password Pattern = 8.32ANP, что означает использование паролей минимальной длины 8 символов, максимальный размер 32 символа, разрешено использование алфавитно-цифровых символов и символов пунктуации. Для подключения специфичных алгоритмов проверки валидности пароля используется параметр Password validation routine.

Подробное описание приводится в [1], раздел «Password Strength and Password Policies».

Помимо использования внутренних механизмов, аутентификация в Caché может быть делегирована операционной системе, Kerberos или LDAP серверам.

Недавно, для одного проекта, мне нужно было проверить, насколько СУБД Caché соответствует требованиям новой редакции стандарту безопасности данных индустрии платежных карт PCI DSS 3.2 принятой в апреле 2016 года.

Соответствие настроек безопасности СУБД Caché требованиям стандарта PCI DSS версии 3.2 [5]


Контролируемый
параметр
парольной
политики

Требования PCI DSS Настройки в Портале управления системой
Проверку подлинности пользователя перед сменой пароля.
8.3
Изучить парольные процедуры и процедуры аутентификации и убедиться в том, что пользователь проходит проверку подлинности перед сменой пароля по телефону, электронной почте, с использованием веб-приложения или иным удаленным способом.
[System] > [Security Management] > [Users] >[Edit User] >

Two-factor Authentication

Для проверки подлинности можно включить двух-факторную авторизацию с применение SMS по мобильному телефону.
Установка уникального первоначального пароля для каждого пользователя и его немедленное изменение при первом входе пользователя.
8.2.6
Установку уникального первоначального пароля для каждого пользователя и его немедленное изменение при первом входе пользователя.
[System] > [Security Management] > [Users] >[Edit User] >

Change password on next login
Максимальный срок действия пароля
8.2.4
90 дней
[System Security]> [System-wide Security Parameters]

Password Expiration Days = 80
Минимальная длина
пароля
8.2.3
7 символов
[System Security]> [System-wide Security Parameters]

Password Pattern = 7.32ANP
Сложность пароля
8.2.3
цифры и символы
[System Security]> [System-wide Security Parameters]

Password Pattern = 7.32ANP
Запрет повторного
использования старых паролей
8.2.5
4 старых пароля
По умолчанию нет. Для реализации можно подключить внешнюю аутентификацию, либо расширить функционал за счет реализации прикладного кода
[System] > [Security Management] > [Users] >[Edit User] >
Password validation routine

Ограничение допустимого числа неправильных
попыток ввода, после превышения которых, осуществляется блокировка учетной записи
8.1.6
6 попыток

8.1.7
продолжительность
блокировки не
менее 30 минут
[System Security]> [System-wide Security Parameters]
Invalid login limit = 6

Disable account if login limit
reached = checked

1.6 Настройка разрыва соединения с базой неактивного соединения


Настройки разрыва соединения с базой для неактивных пользовательских сессий зависят от вида подключения к Caché.

Для SQL и объектного доступа через TCP параметр задается в разделе портала управления [Home] > [Configuration] > [SQL Settings] > [General SQL Settings], параметр TCP Keep Alive interval (in seconds): установить в значение 900, что будет соответствовать 15 минутам.

Для веб доступа параметр задается в настройке «No Activity Timeout» для [Home] > [Configuration] > [CSP Gateway Management]. Значение по умолчанию нужно заменить на 900 секунд, и включить параметр «Применить тайм-аут ко всем подключениям»

2 Протоколирование событий


2.1 Общие настройки


Чтобы разрешить протоколирование событий аудита необходимо включить данную опцию для всего экземпляра СУБД Caché. Для этого надо зайти в Портал Управления системой на страницу управления Аудитом [Home] > [Security Management] > [Auditing], и убедиться, что опция «Disable Auditing» доступна, а опция «Enable Auditing» — недоступна, что означает, что аудит включен. Обратное означает, что аудит выключен.

Если аудит выключен, то его надо включить, выбрав пункт меню «Enable Auditing». Просмотр журнала событий возможен через Портал управления системой: [Home] > [Security Management] > [Auditing] > [View Audit Database]


Также имеются системные классы (утилиты) для просмотра журнала событий. В журнале событий регистрируются, в том числе, следующие данные:

  • Дата и время
  • Тип события
  • Имя учетной записи (user identification)

Доступ к данным аудита управляется ресурсом %DB_CACHEAUDIT Для отключения публичного доступа к данному ресурсу, надо убедиться, что в свойствах данного ресурса для Public закрыты как чтение (Read), так и запись (Write). Доступ к списку ресурсов возможен в портале управления системой [Home] > [Security Management] > [Resources] > [Edit Resource], после чего для выбранного ресурса надо нажать ссылку Edit.

По умолчанию для ресурса %DB_CACHEAUDIT выделена одноименная роль %DB_CACHEAUDIT Чтобы ограничить доступ пользователей к журналам регистрации событий необходимо установить список пользователей, которые входят в данную роль, что может быть сделано и портала управления системой:

[Home] > [Security Management] > [Roles] > [Edit Role] после чего необходимо выбрать кнопку Edit для роли %DB_CACHEAUDIT

2.2 Перечень протоколируемых типов событий


2.2.1 Протоколирование доступа к таблицам, содержащим данные платежных карт (PCI DSS 10.2.1)


Протоколирование доступа к таблицам (наборам данных), содержащих данные платежных карт, осуществляется с помощью следующих механизмов:

1. Системного механизма аудита, который делает запись события типа «ResourceChange» в журнал событий при изменении прав доступа к ресурсу, отвечающему за хранение данных платежных карт (доступ для журнала аудита для просмотра вызывается через портал управления системой [Home] > [Security Management] > [Auditing] > [View Audit Database]);

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

[System] > [Security Management] > [Configure User Audit Events] > [Edit Audit Event]

2.2.2 Протоколирование попыток использования административных привилегий (PCI DSS 10.2.2)


В СУБД Caché протоколируются действия всех пользователей, настройка способа протоколирования выполняется через указание событий, подлежащих протоколированию
[Home] > [Security Management] > [Auditing] > [Configure SystemEvents] Должно быть включено протоколирование всех системных событий.

2.2.3 Протоколирование изменений журнала регистрации событий (PCI DSS 10.2.3)


В СУБД Caché используется единый журнал аудита, который не может быть изменен, за исключением естественного изменения его наполнения и фактов возникновения ошибки, очистки журнала, изменения списка аудируемых событий и т.д., которые вызывают соответствующую запись события AuditChange в журнал.

Задача протоколирования события AuditChange выполнена включением аудита всех событий (см. 2.2.2).

2.2.4 Протоколирование неуспешных попыток получения логического доступа (PCIDSS 10.2.4)


Задача протоколирования неуспешной попытки получения логического доступа выполнена включением аудита всех событий (см. 2.2.2).

По факту попытки получения логического доступа в журнале аудита создается событие «LoginFailure».

2.2.5 Протоколирование попыток получения доступа в систему (PCI DSS 10.2.5)


Задача протоколирования попытки получения доступа в систему выполнена включением аудита всех событий (см. 2.2.2).

По факту неудачной попытки получения доступа в журнале аудита создается событие «LoginFailure». По факту удачной попытки получения доступа в журнале аудита создается событие «Login».

2.2.6 Протоколирование изменения параметров аудита (PCI DSS 10.2.6)


Задача протоколирования изменений параметров аудита выполнена включением аудита всех событий (см. 2.2.2).

По факту попытки получения логического доступа в журнале аудита создается событие «AuditChange».

2.2.7 Протоколирование создания и удаления системных объектов (PCI DSS 10.2.7)


В СУБД Caché протоколируется создание, изменение и удаление следующих системных объектов: ролей, привилегий, ресурсов, пользователей.

Задача протоколирования создания и удаления системных объектов выполнена включением аудита всех событий (см. 2.2.2).

По факту создания, изменения и удаления системных объектов в журнале аудита создаются события «ResourceChange», «RoleChange», «ServiceChange», «UserChange».

2.3 Защита журналов регистрации событий


Необходимо убедиться, что доступ к ресурсу %DB_CACHEAUDIT ограничен. То есть права на чтение и запись в данный ресурс имеют только администраторы или лица, в чьи обязанности входит мониторинг логов.

Следуя вышеизложенным рекомендациям я установил СУБД Caché в максимальном безопасном режиме. Для демонстрации выполнения требования стандарта PCI DSS пункта 8.2.5 «Запрет повторного использования старых паролей» реализовал небольшую программу, которая будет запускаться системой при редактировании пользователем своего пароля и проверять повторность его применения.

Для установки этой программы нужно импортировать исходный код с помощью Caché Studio, Atelier или страницы импорта классов через панель управления
ROUTINE PASSWORD
PASSWORD ; Программа проверки паролей
#include %occInclude
CHECK(Username,Password) PUBLIC {
	if '$match(Password,"(?=.*[0-9])(?=.*[a-zA-Z]).{7,}") quit $$$ERROR($$$GeneralError,"Пароль не соответствует стандарту PCI_DSS_v3.2")
	
        set Remember=4 ;Количество последних паролей, которых нельзя использовать по PCI-DSS 
	set GlobRef="^PASSWORDLIST" ; Имя глобальной ссылки
  	set PasswordHash=$System.Encryption.SHA1Hash(Password)
	if $d(@GlobRef@(Username,"hash",PasswordHash)){
	   	quit $$$ERROR($$$GeneralError,"Этот пароль уже использовался")
	}
	set hor=""
  	for i=1:1 {
	  	; Обходим узлы по хронологии от новых к старым
	  	set hor=$order(@GlobRef@(Username,"datetime",hor),-1) 
	  	quit:hor=""
	  	; Удаляем старый сверх лимита
	  	if i>(Remember-1) {
		  	set hash=$g(@GlobRef@(Username,"datetime",hor))
		  	kill @GlobRef@(Username,"datetime",hor)
		  	kill:hash'="" @GlobRef@(Username,"hash",hash)
	  	}
  	}
  	; Сохраним текущий
  	set @GlobRef@(Username,"hash",PasswordHash)=$h
  	set @GlobRef@(Username,"datetime",$h)=PasswordHash
  	quit $$$OK
}


А в портале управления сохраним имя этой программы.


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


Разработчики СУБД ограничили вывод списка 1000 элементами. Мой эталон затерялся где то внизу и в список не попадал. После консультации со службой поддержки Интерсистемс WRC я получил рекомендации, что решить эту проблему можно, создав в системной области специальный узел глобала командой:

%SYS>set ^CacheTemp.MgtPortalSettings($Username,"MaxUsers")=5000

Именно так можно было увеличить количество выводимых пользователей в ниспадающем списке. Исследуя этот глобал, я нашел в нем еще много других полезных сохранённых настроек текущего пользователя. Но есть неудобство: этот глобал имеет маппинг во временную базу данных CacheTemp и после перезагрузки удалится. И эту проблему можно решить только сохраняя этот глобал перед остановом системы и восстанавливая при старте.

Для этого я создал две программы ^%ZSART и ^%ZSTOP с требуемой функциональностью.

Исходный код программы %ZSTOP
%ZSTOP ; останов
	quit
SYSTEM
	;сохраним предпочтения пользователей в неубиваемом глобале
	merge ^tmpMgtPortalSettings=^CacheTemp.MgtPortalSettings
	quit


Исходный код программы %ZSTART
%ZSTART ; старт
	quit
SYSTEM
	;восстановим предпочтения пользователей из неубиваемого глобала
	if $data(^tmpMgtPortalSettings) merge ^CacheTemp.MgtPortalSettings=^tmpMgtPortalSettings
	quit
   


И возвращаясь к безопасности и требованиям стандарта нельзя не сказать о процедуре резервного копирования. Стандарт PCI DSS предъявляет требования к резервному копированию не только данных, но и к журналам протоколирования событий. В СУБД Caché все протоколируемые события записываются в базу данных CACHEAUDIT, которая наряду с другими базами может включаться в список баз данных для резервного копирования.

В поставке СУБД Caché уже есть несколько готовых заданий для резервного копирования,
но они мне не всегда подходили. Каждый раз, в том или ином проекте требовались особенности, которых не было в заданиях «из коробки». Для одного проекта требовалось автоматизировать контроль за количеством копий с возможностью удаления старых. Для другого, нужно было перед копирование оценить прогнозируемый занимаемый объем будущего файла. И я реализовал свою программу резервного копирования.

CustomListBackup.cls
Include %occKeyword

/// Класс задачи резервного копирования
Class %SYS.Task.CustomListBackup Extends %SYS.Task.Definition [ LegacyInstanceContext ]
{

/// Если ..AllDatabases=1, то в копию включать все базы данных ..PrefixIncludeDB и ..IncludeDatabases - игнорируются
Property AllDatabases As %Integer [ InitialExpression = 0 ];

/// Если ..AllDatabases=1, то в копию включать все базы данных , исключая из ..IgnoreForAllDatabases через запятую
Property IgnoreForAllDatabases As %String(MAXLEN = 32000) [ InitialExpression = "При AllDatabases=0 не применяется " ];

/// Если ..IgnoreTempDatabases=1, то исключать временные базы
Property IgnoreTempDatabases As %Integer [ InitialExpression = 1 ];

/// Если ..IgnorePreparedDatabases=1, то исключать предустановленные базы
Property IgnorePreparedDatabases As %Integer [ InitialExpression = 1 ];

/// Если ..AllDatabases=0 и если PrefixIncludeDB не пустое, то будем бэкапить все бд, имена которых начинаются на ..PrefixIncludeDB
Property PrefixIncludeDB As %String [ SqlComputeCode = {S {*}=..ListNS()}, SqlComputed ];

/// Если ..AllDatabases=0, то в копию включать все базы данных из ..IncludeDatabases , через запятую
Property IncludeDatabases As %String(MAXLEN = 32000) [ InitialExpression = {"При AllDatabases=1 не применяется "_..ListDB()} ];

/// Имя задачи в общем списке
Parameter TaskName = "CustomListBackup";

/// Путь, где хранить бэкапы
Property DirBackup As %String(MAXLEN = 1024) [ InitialExpression = {##class(%File).NormalizeDirectory("Backup")} ];

/// Путь, куда писать протокол
Property DirBackupLog As %String(MAXLEN = 1024) [ InitialExpression = {##class(%File).NormalizeDirectory("Backup")} ];

/// Тип копии (Full-Полный, Incremental-Инкрементальный, Cumulative-Комулятивный)
Property TypeBackup As %String(DISPLAYLIST = ",Full,Incremental,Cumulative", VALUELIST = ",Full,Inc,Cum") [ InitialExpression = "Full", SqlColumnNumber = 4 ];

/// Префикс имени файла бэкапа
Property PrefixBackUpFile As %String [ InitialExpression = "back" ];

/// Максимальное количество файлов бэкап, самые старые удалять
Property MaxBackUpFiles As %Integer [ InitialExpression = 3 ];

ClassMethod DeviceIsValid(Directory As %String) As %Status
{
 
	If '##class(%Library.File).DirectoryExists(Directory) quit $$$ERROR($$$GeneralError,"Directory does not exist")
	quit $$$OK
}

ClassMethod CheckBackup(Device, MaxBackUpFiles, del = 0) As %Status
{
 
	set path=##class(%File).NormalizeFilename(Device)
	quit:'##class(%File).DirectoryExists(path) $$$ERROR($$$GeneralError,"Директория "_path_" не существует") 
	set max=MaxBackUpFiles
	set result=##class(%ResultSet).%New("%File:FileSet")
	set st=result.Execute(path,"*.cbk",,1)
	while result.Next()
	{	If result.GetData(2)="F"	{
			continue:result.GetData(3)=0
			set ts=$tr(result.GetData(4),"-: ")
			set ts(ts)=$lb(result.GetData(1),result.GetData(3))			
		}
	}
	#; Обойдем все файлы начиная с самого нового
	set i="" for count=1:1 { set i=$order(ts(i),-1) quit:i=""
		#; Получаем прирост в байтах как разницу размера от предыдущего бэкап
		if $data(size),'$data(delta) set delta=size-$lg(ts(i),2)
		#; Получим размер в байтах самого свежего файла бэкап
		if '$data(size) set size=$lg(ts(i),2)
		#; Если количество файлов бэкап больше или равно максимального, то удаляем самые старые вместе с логами
		if count'<max {
			set cbk=$lg(ts(i),1)
			set log=$replace($lg(ts(i),1),".cbk",".log")
			if del { if ##CLASS(%File).Delete(cbk)
					if ##CLASS(%File).Delete(log)
			}
		}
	}
	do result.%Close()
	If $$$isUNIX quit $$$OK ##; Для линух не считаем	
	#; Высчитаем количество байт свободного места на диске
	set drive=$e(path,1)
	do ##CLASS(%File).GetDirectorySpace(drive_":/",.free,.total,0)
	#; Возращаем ошибку если прогнозируемый размер нового бэкап больше чем свободное место
	quit:($g(size)+$g(delta))>$g(free) $$$ERROR($$$GeneralError,"Прогнозируемый размер нового файла бэкап больше, чем свободное место на диске:("_$g(size)_"+"_$g(delta)_")>"_$g(free)) 
	quit $$$OK
}

Method OnTask() As %Status
{
 
	do $zu(5,"%SYS")
	set list=""
	merge oldDBList=^SYS("BACKUPDB")
	kill ^SYS("BACKUPDB")
	#; Добавление новых свойств для задание запуска бэкап
	set status=$$$OK
	try {
		##; Проврка на количество копий бд, если нужно то удалить самую старую
		##; Проверка на оставшийся объем на диске и прогнозируемый размер нового файла
		set status=..CheckBackup(..DirBackup,..MaxBackUpFiles,1)
		quit:$$$ISERR(status)
		#; Все базы данных
		if ..AllDatabases {
			set vals=""
			set disp=""
			set rss=##class(%ResultSet).%New("Config.Databases:List")
			do rss.Execute()
			while rss.Next(.sc) { 
				if ..IgnoreForAllDatabases'="",(","_..IgnoreForAllDatabases_",")[(","_$zconvert(rss.Data("Name"),"U")_",") continue
				if ..IgnoreTempDatabases continue:..IsTempDB(rss.Data("Name"))
				if ..IgnorePreparedDatabases continue:..IsPreparedDB(rss.Data("Name"))
				set ^SYS("BACKUPDB",rss.Data("Name"))=""
			}
		}
		else {
			#; если свойство PrefixIncludeDB не пустое, то будем бэкапить все бд имена которых начинаются на ..PrefixIncludeDB
			if ..PrefixIncludeDB'="" {
					set rss=##class(%ResultSet).%New("Config.Databases:List")
					do rss.Execute(..PrefixIncludeDB_"*")
					while rss.Next(.sc) { 
						if ..IgnoreTempDatabases continue:..IsTempDB(rss.Data("Name"))
						set ^SYS("BACKUPDB",rss.Data("Name"))=""
					}
			}
			#; Включим в список конкретные бд
			if ..IncludeDatabases'="" {
				set rss=##class(%ResultSet).%New("Config.Databases:List")
				do rss.Execute("*")
				while rss.Next(.sc) { 
					if ..IgnoreTempDatabases continue:..IsTempDB(rss.Data("Name"))
					if (","_..IncludeDatabases_",")'[(","_$zconvert(rss.Data("Name"),"U")_",") continue
					set ^SYS("BACKUPDB",rss.Data("Name"))=""
				}
			}
		}
		do ..GetFileName(.backFile,.logFile)
		set typeB=$zconvert($e(..TypeBackup,1),"U")
		set:"FIC"'[typeB typeB="F"
		set res=$$BACKUP^DBACK("",typeB,"",backFile,"Y",logFile,"NOINPUT","Y","Y","","","")
		if 'res set status=$$$ERROR($$$GeneralError,"Ошибка: "_res)
	} catch {	set status=$$$ERROR($$$GeneralError,"Ошибка: "_$ze) 
				set $ze=""
	  }
	kill ^SYS("BACKUPDB")
	merge ^SYS("BACKUPDB")=oldDBList
	quit status
}

/// Получить имена файлов
Method GetFileName(aBackupFile, ByRef aLogFile) As %Status
{
 
	set tmpName=..PrefixBackUpFile_"_"_..TypeBackup_"_"_$s(..AllDatabases:"All",1:"List")_"_"_$zd($h,8)_$tr($j($i(cnt),3)," ",0)
	do {
		s aBackupFile=##class(%File).NormalizeFilename(..DirBackup_"/"_tmpName_".cbk")
	} while ##class(%File).Exists(aBackupFile)
	set aLogFile=##class(%File).NormalizeFilename(..DirBackupLog_"/"_tmpName_".log")
	quit 1
}

/// Проверить предустановленная ли база данных
ClassMethod IsPreparedDB(name)
{
 
	if (",ENSDEMO,ENSEMBLE,ENSEMBLEENSTEMP,ENSEMBLESECONDARY,ENSLIB,CACHESYS,CACHELIB,CACHETEMP,CACHE,CACHEAUDIT,DOCBOOK,USER,SAMPLES,")[(","_$zconvert(name,"U")_",") quit 1
	quit 0
}

/// Проверить временная ли база данных
ClassMethod IsTempDB(name)
{
 
	quit:$zconvert(name,"U")["TEMP" 1
	quit:$zconvert(name,"U")["SECONDARY" 1
	quit 0
}

/// Получить список имен баз данных через запятую
ClassMethod ListDB()
{
 
	set list=""
	set rss=##class(%ResultSet).%New("Config.Databases:List")
	do rss.Execute()
	while rss.Next(.sc) { 
		set list=list_","_rss.Data("Name") 
	}
	quit list
}

ClassMethod ListNS() [ Private ]
{
 
	set disp=""
	set tRS = ##class(%ResultSet).%New("Config.Namespaces:List")
	set tSC = tRS.Execute()
	While tRS.Next() {	
				set disp=disp_","_tRS.GetData(1)
	}
	set %class=..%ClassName(1)
	$$$comSubMemberSet(%class,$$$cCLASSproperty,"PrefixIncludeDB",$$$cPROPparameter,"VALUELIST",disp)
	quit ""
}

ClassMethod oncompile() [ CodeMode = generator ]
{
 
	$$$defMemberKeySet(%class,$$$cCLASSproperty,"PrefixIncludeDB",$$$cPROPtype,"%String")
	set updateClass=##class("%Dictionary.ClassDefinition").%OpenId(%class)
	set updateClass.Modified=0
	do updateClass.%Save()
	do updateClass.%Close()
}

}


Все основные пожелания в нем реализованы: и ограничение количество копий с удалением старых и прогноз объема нового файла, и разные способы выбора или исключения из списка баз данных. Импортируем в систему и создаем новое задание с помощью Менеджера задач.



И включаем базу данных в список копируемых баз.

Все примеры приведены для версии СУБД Caché 2016.1. Примеры приведены исключительно в ознакомительных целях и установка их в продуктовую систему нужно делать только после серьезного тестирования. Буду рад, если приведенный код помог кому нибудь в работе, или уберег от ошибок.

Репозиторий в Github

В подготовке этой статьи использовались материалы:

  1. Caché Security Administration Guide (InterSystems)
  2. Caché Installation Guide. Preparing for Caché Security (InterSystems)
  3. Caché System Administration Guide (InterSystems)
  4. Introduction to Caché. Caché Security (InterSystems)
  5. PCI DSS.RU. Требования и процедура аудита безопасности. Версия 3.2
InterSystems 77,08
Вендор: СУБД Caché, OLAP DeepSee, шина Ensemble
Поделиться публикацией
Комментарии 13
  • 0
    Из раздела на проверку соответствия
    Сложность пароля: цифры и символы
    Password Pattern = 7.32ANP

    7.32ANP — это от 7 до 32 буквы или цифры или знаки пунктуации
    One or more pattern codes. If more than one code is specified, the pattern is satisfied by matching any one of the codes.
    Pattern Matching
    Надо указывать программу
    • 0
      Действительно, ошибка.
      В программу ^PASSWORD добавил
      проверку
      ROUTINE PASSWORD
      PASSWORD ; Программа проверки паролей
      #include %occInclude
      CHECK(Username,Password) PUBLIC {
      	if $l(Password)<7 quit $$$ERROR($$$GeneralError,"Этот пароль меньше 7 символов") 
      	if $l(Password)>32 quit $$$ERROR($$$GeneralError,"Этот пароль больше 32 символов")
      	if $tr(Password,"0123456789")=Password quit $$$ERROR($$$GeneralError,"Этот пароль не содержит цифры")
      	if $tr(Password,"?!@#$%^&*()-[]{}<>+=,._~\|/")=Password quit $$$ERROR($$$GeneralError,"Этот пароль не содержит знаки пунктуации")
      	if $tr(Password,"qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM")=Password quit $$$ERROR($$$GeneralError,"Этот пароль не содержит символы")
      ...
      • 0
        Проверку на буквы, цифры, символы ( вместо $translate ) в программе лучше переписать через всё тот же Pattern Matching. Ибо русский ( или другие ) символы, utf-8, настройки инстанса и т.д ;)
        • 0
          Главное, начать улучшать код,
          потом бывает трудно остановиться
          ROUTINE PASSWORD
          PASSWORD ; Программа проверки паролей
          #include %occInclude
          CHECK(Username,Password) PUBLIC {
          	if '$match(Password,"(?=.*[0-9])(?=.*[a-zA-Z]).{7,}") quit $$$ERROR($$$GeneralError,"Пароль не соответствует стандарту PCI_DSS_v3.2")
          ...
          
          • 0
            Это да, соглашусь :))
            // s p = Password
            Q ($l(p)>7) && (p?.E1.A.E) && (p?.E1.N.E) && (p?.E1.P.E)
            
            • 0
              На гитхаб? :)
              // s p = Password
              Q ($l(p)>7) && (p?.E1.N.E) && (p?.E1.(1.A,1.P).E)  // длина,цифры,символы
              
  • 0
    Если аудит выключен, то его надо включить, выбрав пункт меню «Enable Auditing».
    И помнить, что в менеджере задач по умолчанию запущена программа очистки журнала аудита. В последней версии 2017.2 «Очистить всю информацию для аудита с момента переключения журнала», а в предыдущих ( точно в 2013, 2014 ) все что старше 2 месяцев
    • 0
      Разработчики СУБД ограничили вывод списка 1000 элементами

      Откройте для себя удивительный мир CLI ( command line interface ) — запускаете терминал, заходите в область %SYS, набираете do ^SECURITY
      • 0
        Подскажите, в каком месте диалога утилита ^SECURITY позволит создать нового пользователя копированием настроек из уже существующего? Может это уже есть 2017.2?

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

    Самое читаемое