Настройка мандатного управления доступом(МРД) с Kerberos аутентификацией в ЕПП, Apache2, Postgres#
Исходные данные#
Имеется сервер контроллера домена FreeIPA:
имя домена astra.aaa
администратор домена admin@astra.aaa
пользователь домена user-01@astra.aaa
имя сервера dc-01.astra.aaa
сервер имеет постоянный IP-адрес, например, 192.168.1.20
Веб-сервер располагается отдельно:
имя сервера websrv-01.astra.aaa
сервер должен быть введен в домен
на сервере установлен и настроен web-сервер Apache2
сервер имеет постоянный IP-адрес, например, 192.168.1.21
Сервер базы данных располагается отдельно:
имя сервера dbsrv-01.astra.aaa
сервер должен быть введен в домен
на сервере должна быть установлена и настроенная СУБД Postgresql
сервер имеет постоянный IP-адрес, например, 192.168.1.23
Пользовательский компьютер располагается на отдельном компьютере:
имя компьютера pc-01.astra.aaa
компьютер должен быть введен в домен
компьютер имеет постоянный IP-адрес, например, 192.168.1.22
Основная концепция, реализация веб-приложения на языке программирования PHP с МРД#
Контроллер домена Freeipa, веб сервер Apache2 и СУБД Postgres предварительно настроены для использования МРД и kerberos аутентификации. Пользователь домена при входе в сеанс на своём компьютере выбирает уровень и категорию из доступных для него, далее при отправке запроса из браузера веб сервер Apache2 получает классификационную метку пользователя и его билет kerberos. Веб сервер Apache2 производит аутентификацию пользователя и если она прошла успешно, то обработчик запроса переключается в контекст пользователя, включая классификационную метку МРД его сеанса. Далее запускается приложение и создается делегируемый kerberos кэш. Если аутентификации прошла неуспешно, выдается ошибка. Далее веб сервер Apache2 передаёт запрос веб приложению PHP. Веб приложение PHP добавляет в окружение переменную KRB5CCNAME. Далее коннектор php-pgsql, в режиме GSS, производит запрос к БД Postgresql с передачей контекста пользователя, включая классификационную метку МРД. СУБД Postgres так же производит kerberos аутентификацию, авторизацию по правилам МРД и возвращает результаты запроса.
Настройка контроллера домена#
Для настройки контроллера домена необходимо перейти по ссылке и выполнить действия по инструкции:
Настройка компьютера пользователя#
Для настройки компьютера пользователя необходимо перейти по ссылке и выполнить действия по инструкции:
Настройка сервера базы данных#
Для настройки сервера базы данных необходимо перейти по ссылке и выполнить действия по инструкции:
Установка и настройка веб-сервера Apache2#
Для установки и настройки веб-сервера Apache2 необходимо перейти по ссылке и выполнить действия по инструкции:
Установка веб-приложения#
Для установки и настройки веб-приложения необходимо:
Пункт 1#
установить следующие пакеты пакет:
sudo apt install php php-pgsql
Пункт 2#
создать файл index.php по пути /var/www/public_html:
sudo nano /var/www/public_html/index.php
Пункт 3#
файл index.php должен иметь следующее содержимое:
<?php
// Конфигурация подключения к БД
putenv("KRB5CCNAME=" . $_SERVER['KRB5CCNAME']);
$dbConfig = [
'host' => 'test181-dbsrv-01.astra.bbb',
'port' => '5433',
'dbname' => 'demoprimer',
];
// Подключение к базе данных
try {
$dsn = "pgsql:host={$dbConfig['host']};port={$dbConfig['port']};dbname={$dbConfig['dbname']}";
$db = new PDO($dsn, '');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Ошибка подключения к базе данных: " . $e->getMessage());
}
// Обработка удаления записи ДО получения списка записей
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['delete'])) {
try {
$stmt = $db->prepare("DELETE FROM s1.t1 WHERE id = ?");
$stmt->execute([$_GET['delete']]);
// Перенаправление для предотвращения повторного удаления при обновлении страницы
header("Location: ".strtok($_SERVER['REQUEST_URI'], '?'));
exit();
} catch (PDOException $e) {
die("Ошибка при удалении записи: " . $e->getMessage());
}
}
// Обработка остальных CRUD операций
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
session_start();
$currentUser = $_SERVER['REMOTE_USER'];
if (isset($_POST['create'])) {
// Создание новой записи
$stmt = $db->prepare("INSERT INTO s1.t1 (insert_user, insert_date, classificator)
VALUES (?, CURRENT_TIMESTAMP, ?)");
$stmt->execute([$currentUser, $_POST['classificator']]);
} elseif (isset($_POST['update'])) {
// Обновление записи
$stmt = $db->prepare("UPDATE s1.t1
SET classificator = ?
WHERE id = ?");
$stmt->execute([$_POST['classificator'], $_POST['id']]);
}
// Перенаправление для предотвращения повторной отправки формы
header("Location: ".$_SERVER['PHP_SELF']);
exit();
}
// Получение всех записей
$records = $db->query("SELECT maclabel, *, extract(epoch from insert_date) as insert_ts
FROM s1.t1
ORDER BY insert_date DESC")->fetchAll(PDO::FETCH_ASSOC);
// Получение записи для редактирования
$editRecord = null;
if (isset($_GET['edit'])) {
$stmt = $db->prepare("SELECT * FROM s1.t1 WHERE id = ?");
$stmt->execute([$_GET['edit']]);
$editRecord = $stmt->fetch(PDO::FETCH_ASSOC);
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Демонстрационный пример</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; line-height: 1.6; }
h1, h2 { margin: 0 0 20px; }
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; border-radius: 8px; overflow: hidden; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
th, td { padding: 12px 15px; text-align: left; border: 1px solid #ddd; }
th { background-color: #f2f2f2; font-weight: 600; }
tr:nth-child(even) { background-color: #f9f9f9; }
tr:hover { background-color: #f1f1f1; }
form { margin-bottom: 20px; padding: 20px; background: #f9f9f9; border: 1px solid #ddd; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.05); }
label { display: block; margin-bottom: 8px; font-weight: 500; }
input { margin-bottom: 15px; width: 100%; max-width: 500px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; box-sizing: border-box; }
input:focus { outline: none; border-color: #0079C1; box-shadow: 0 0 5px rgba(0,121,193,0.3); }
button { background: #0079C1; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: 500; text-decoration: none; display: inline-block;>
.button { padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: 500; text-decoration: none; display: inline-block; margin-right: 8px; >
button:hover { background: #00588D; }
.actions { white-space: nowrap; }
.uuid { font-family: monospace; font-size: 0.9em; }
.form-row { margin-bottom: 15px; }
.button-cancel { background: #6c757d; }
.button-cancel:hover { background: #5a6268; }
.button-edit { background: #0079C1; color: #fff; }
.button-edit:hover { background: #00588D; }
.button-delete { background: #dc3545; }
.button-delete:hover { background: #bb2d3b; }
</style>
</head>
<body>
<h1>Демонстрационный пример</h1>
<!-- Форма для создания/редактирования -->
<form method="POST">
<h2><?= $editRecord ? 'Редактировать запись' : 'Добавить новую запись' ?></h2>
<?php if ($editRecord): ?>
<input type="hidden" name="id" value="<?= htmlspecialchars($editRecord['id']) ?>">
<?php endif; ?>
<div class="form-row">
<label for="classificator">Наименование:</label>
<input type="text" id="classificator" name="classificator" placeholder="Введите наименование" required
value="<?= htmlspecialchars($editRecord['classificator'] ?? '') ?>">
</div>
<div class="form-row">
<?php if ($editRecord): ?>
<button type="submit" name="update">Обновить</button>
<a href="?" class="button button-cancel" >Отмена</a>
<?php else: ?>
<button type="submit" name="create">Создать</button>
<?php endif; ?>
</div>
</form>
<!-- Таблица с записями -->
<table>
<thead>
<tr>
<th>ID</th>
<th>MAC</th>
<th>Наименование</th>
<th>Создано</th>
<th>Кем создано</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
<?php foreach ($records as $record): ?>
<tr>
<td><?= htmlspecialchars($record['id']) ?></td>
<td><?= htmlspecialchars($record['maclabel']) ?></td>
<td><?= htmlspecialchars($record['classificator']) ?></td>
<td>
<div><?= date('d-m-Y H:i:s', $record['insert_ts']) ?></div>
</td>
<td><?= htmlspecialchars(strtolower($record['insert_user'])) ?></td>
<td class="actions">
<a href="?edit=<?= urlencode($record['id']) ?>" class="button button-edit">Редактировать</a>
<a href="?delete=<?= urlencode($record['id']) ?>" class="button button-delete" onclick="return confirm('Вы уверены?')">Удалить</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</body>
</html>
Сценарий проверки работы МРД в веб-приложении#
Важно
Документация дорабатывается по мере развития продуктов Группы Астра и по пожеланиям пользователей.
Ваши пожелания и замечания направляйте на почту docs@astralinux.ru