Защита сайта и API
Для защиты сайта и API нужно:
Создание Keycloak-сервера для аутентификации пользователей
Чтобы настроить аутентификацию на сайте, нужно создать провайдера, который будет удостоверять пользователей. В качестве примера будет настроен экземпляр Keycloak.
Для этого понадобится виртуальная машина, на которую будет установлен провайдер аутентификации Keycloak.
Создание виртуальной машины
Создайте виртуальную машину с публичным IP-адресом, по которому пользователи смогут перейти и выполнить аутентификацию:
-
В списке сервисов выберите Elastic Cloud Server.
-
Нажмите Create ECS в правом верхнем углу.
-
В поле AZ выберите Random.
-
Выберите конфигурацию с 2 vCPUs и 4 GiB. Например, «s6.large.2» или «s7n.large.2».
-
В поле Image выберите Public Image → Ubuntu → Ubuntu 20.04 server.
-
Нажмите Next: Configure Network.
-
В поле Network выберите виртуальную сеть и подсеть, в которой будет находиться виртуальная машина.
-
В поле Security Group нажмите Create Security Group.
-
На новой вкладке нажмите Create Security Group.
-
В поле Name введите keycloak.
-
В поле Template выберите Custom — шаблон без дополнительных настроек.
-
Нажмите OK.
-
Нажмите Manage Rule.
-
Перейдите во вкладку Inbound Rule.
-
Нажмите Add Rule.
-
В поле Priority введите 1.
-
В поле Protocol & Port введите 8443. По этому порту будет открыт доступ к серверу из интернета.
-
Нажмите OK.
-
Вернитесь на предыдущую вкладку, в которой создавали виртуальную машину.
-
Обновите список групп безопасности и выберите keycloak.
-
В поле EIP выберите Auto assign.
-
Нажмите Next: Configure Advanced Settings.
-
В поле ECS Name укажите название виртуальной машины.
-
Введите и повторите пароль для подключения к серверу.
-
Нажмите Next: Confirm.
-
Проверьте конфигурацию виртуальной машины.
-
Нажмите Apply Now.
Сервер создан, настроен и готов к работе.
Установка Keycloak
Чтобы установить Keycloak на сервер:
-
В списке сервисов выберите Elastic Cloud Server.
-
Напротив виртуальной машины, которую вы создали ранее, нажмите Remote Login.
-
В консоли введите:
-
root — имя пользователя;
-
пароль, указанный при создании сервера.
-
-
Скачайте Docker:
curl -fsSL https://get.docker.com -o get-docker.sh -
Установите Docker:
sh get-docker.sh -
Сгенерируйте самоподписанный сертификат:
openssl req -newkey rsa:2048 -nodes -keyout server.key.pem -x509 -days 3650 -out server.crt.pem -
Смените права доступа к файлу server.key.pem:
chmod 755 server.key.pem -
Запустите контейнер с Keycloak:
docker run -d --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -e KC_HTTPS_CERTIFICATE_FILE=/opt/keycloak/conf/server.crt.pem -e KC_HTTPS_CERTIFICATE_KEY_FILE=/opt/keycloak/conf/server.key.pem -v $PWD/server.crt.pem:/opt/keycloak/conf/server.crt.pem -v $PWD/server.key.pem:/opt/keycloak/conf/server.key.pem -p 8443:8443 quay.io/keycloak/keycloak:19.0.1 start-dev
Keycloak установлен.
Настройка Keycloak
-
В списке сервисов выберите Elastic Cloud Server.
-
Скопируйте EIP — публичный IP-адрес виртуальной машины, на которую вы установили Keycloak.
-
Чтобы попасть в консоль управления Keycloak, перейдите по адресу:
https://ip-адрес-сервера:8443/adminНапример, если IP-адрес сервера 203.0.113.1, нужно перейти по:
https://203.0.113.1:8443/admin -
Так как на сервере установлен самоподписанный SSL-сертификат, при переходе возникнет уведомление «Подключение не защищено». Чтобы попасть в Keycloak, нажмите Дополнительные → Перейти на сайт.
-
Войдите в Keycloak:
-
Username or email — admin;
-
Password — admin.
-
-
Перейдите в раздел Clients в левом меню.
-
Нажмите Create Client.
-
В поле Client Type выберите OpenID Connect.
-
Придумайте и введите в поле Client ID идентификатор для сайта, который находится в OBS.
-
Нажмите Next.
-
Активируйте параметр Client authentication.
-
Активируйте опцию Implicit flow.
-
Нажмите Save.
-
Введите адрес сайта, который загружен в OBS, в следующие поля:
-
Root URL
-
Home URL
-
Valid redirect URIs
Чтобы узнать адрес сайта, откройте страницу сервиса OBS и нажмите на название бакета, в котором находится сайт. Затем перейдите в раздел Basic Configurations → Static Website Hosting.
-
-
Нажмите Save.
Сервер аутентификации Keycloak создан.
Аутентификация на сайте
Теперь аутентификацию нужно добавить на сайт. Она будет выполняться с помощью сервера Keycloak.
В разделе Публикация статического веб-сайта для работы с API вы уже загрузили сайт, который работает с API, но он не поддерживает аутентификацию пользователей. Нужно загрузить новый сайт с поддержкой аутентификации через Keycloak. Для размещения файлов сайта используйте тот же бакет, который вы создавали ранее.
Порядок действий при загрузке точно такой же, как и ранее. Отличаются файлы сайта, которые нужно загрузить.
Публикация сайта
Чтобы опубликовать сайт в OBS:
-
Скачайте и распакуйте архив с файлами сайта.
-
Откройте файл settings.json.
-
Укажите настройки в конфигурационном файле:
-
api_url — адрес API. Узнать его можно в разделе Узнать API URL.
-
oauth_endpoint — адрес сервера Keycloak. В URL замените example на IP-адрес вашего сервера Keycloak. Это адрес виртуальной машины, которую вы создали в разделе Настройка Keycloak.
-
client_id — Client ID в Keycloak. Он указывался в разделе Настройка Keycloak. Узнать Client ID можно на странице Keycloak по адресу https://ip-адрес-сервера:8443/admin в разделе Clients.
-
response_type — без изменений.
-
scope — без изменений.
-
nonce — без изменений.
-
redirect_url — адрес вашего сайта в Object Storage Service. Узнать URL можно в разделе Basic Configurations → Static Website Hosting.
-
-
Сохраните изменения в файле.
-
Откройте ранее созданный бакет и перейдите в раздел Objects в правом меню.
-
Выделите и удалите все ранее загруженные файлы в бакете.
-
Нажмите Upload Object.
-
В поле Object Permission выберите Public Read.
-
Перетащите содержимое каталога react-js-oauth-spa в форму загрузки OBS.
-
Нажмите Upload.
ПримечаниеЕсли у вас возникли проблемы во время загрузки файлов сайта, воспользуйтесь OBS Browser+.
-
Перейдите в раздел Basic Configurations → Static Website Hosting.
-
Перейдите по адресу, который указан в поле Hosted Website URL.
-
Откроется страница аутентификации Keycloak. Введите:
-
логин — admin;
-
пароль — admin.
-
-
Нажмите Sign In. После успешной аутентификации вы будете перенаправлены обратно на сайт, а в правом верхнем углу появится название аккаунта.
-
Проверьте добавление, отображение и удаление записей на сайте.
Сайт опубликован. Теперь каждый посетитель сайта должен пройти аутентификацию. При этом API все равно доступен любому анонимному пользователю. Чтобы запретить анонимный доступ, нужно настроить аутентификацию в API.
Аутентификация в API
Для аутентификации в API нужно создать отдельную функцию валидации запросов к API. API Gateway будет вызывать ее при обращении к API. Функция будет проверять входящий access_token и разрешать обращение к API только валидным пользователям.
API Gateway умеет кешировать ответ от функции валидации. Это позволяет не вызывать функцию валидации при каждом обращении к API.
Использование готовой функции
-
Внимание
По умолчанию Node.js не обрабатывает самоподписанный сертификат, который используется в функции аутентификации. Чтобы аутентификация работала несмотря на самоподписанный сертификат, в код добавлена строка: process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;. Это небезопасно, но допустимо в рамках практической работы.
-
В списке сервисов выберите FunctionGraph.
-
Нажмите Create Function в правом верхнем углу.
-
В поле Function name укажите название функции, например «API-AUTH».
-
В списке Runtime выберите Node.js 12.13.
-
В поле Handler нужно указать название файла и название функции. Если использовали код из примера, оставьте значение по умолчанию.
-
В поле Code Entry Mode выберите Upload ZIP и загрузите архив с функцией.
-
Нажмите Create Function.
Функция загружена в FunctionGraph.
Для работы функции нужно указать переменные окружения. Для этого:
-
В разделе Functions сервиса FunctionGraph нажмите на название загруженной ранее функции.
-
Перейдите во вкладку Configuration.
-
В разделе Environment Variables нажмите Add Now и добавьте два параметра:
Идентификатор клиента:
-
Key — audience;
-
Value — account.
Адрес провайдера, выписавшего токен:
-
Key — issuer;
-
Value — адрес сервера Keycloak https://ip-адрес-сервера:8443/realms/master.
-
-
Нажмите Save напротив каждого параметра.
-
В правом верхнем углу нажмите Save.
Функция загружена и настроена. Перейдите к разделу Настройка API Gateway.
Ручное создание и загрузка функции авторизации
-
Создайте каталог для хранения кода функции:
mkdir catalog-name -
Перейдите в созданный каталог:
cd catalog-name -
Инициализируйте проект:
npm init -y -
Установите зависимости:
npm install jsonwebtoken -
Создайте файл index.js:
touch index.js -
Добавьте в файл index.js код:
exports.handler = async (event, context) => {const jwt = require('jsonwebtoken');const request = require('request');const util = require('util');const requestWrapper = util.promisify(request);const audience = process.env.audience;const issuer = process.env.issuer;process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;let body = {status: "deny"};try {const oauthConfig = await requestWrapper(`${issuer}/.well-known/openid-configuration`);const keyUrl = JSON.parse(oauthConfig.body).jwks_uri;const keys = await requestWrapper(keyUrl);const key = JSON.parse(keys.body).keys[0].x5c[0];const signingCertificate = `-----BEGIN CERTIFICATE-----\n${key}\n-----END CERTIFICATE-----`;//verify tokenconst token = event.headers["x-access-token"];const jwttoken = jwt.verify(token, signingCertificate, {audience: audience, issuer: issuer});body.status = "allow";} catch (e) {console.log(e);}const output = {"statusCode": 200,"body": JSON.stringify(body)}return output;}ВниманиеПо умолчанию Node.js не обрабатывает самоподписанный сертификат, который используется в функции аутентификации. Чтобы аутентификация работала несмотря на самоподписанный сертификат, в код добавлена строка: process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;. Это небезопасно, но допустимо в рамках практической работы.
-
Создайте ZIP-архив с содержимым каталога catalog-name. Архив должен содержать файлы index.js, package.jsos, package-lock.json и каталог node_modules.
Функция создана. Чтобы загрузить ее в FunctionGraph:
-
В списке сервисов выберите FunctionGraph.
-
Нажмите Create Function в правом верхнем углу.
-
В поле Function name укажите название функции, например «API-AUTH».
-
В списке Runtime выберите Node.js 12.13.
-
В поле Handler нужно указать название файла и название функции. Если использовали код из примера, оставьте значение по умолчанию.
-
В поле Code Entry Mode выберите Upload ZIP и загрузите архив с функцией.
-
Нажмите Create Function.
Функция загружена в FunctionGraph.
Для работы функции нужно указать переменные окружения. Для этого:
-
В разделе Functions сервиса FunctionGraph нажмите на название загруженной ранее функции.
-
Перейдите во вкладку Configuration.
-
В разделе Environment Variables нажмите Add Now и добавьте два параметра:
Идентификатор клиента:
-
Key — audience;
-
Value — account.
Адрес провайдера, выписавшего токен:
-
Key — issuer;
-
Value — адрес сервера Keycloak https://ip-адрес-сервера:8443/realms/master.
-
-
Нажмите Save напротив каждого параметра.
-
В правом верхнем углу нажмите Save.
Функция загружена и настроена. Перейдите к разделу Настройка API Gateway.
Настройка API Gateway
API Gateway нужно настроить на использование функции валидации. Для этого сначала нужно создать Custom Authorizer на уровне API Gateway:
-
В списке сервисов выберите API Gateway.
-
Перейдите в раздел API Publishing → Custom Authorizers.
-
Нажмите Create Custom Authorizer в правом верхнем углу.
-
В поле Name укажите название.
-
В поле Type выберите Frontend.
-
В поле Function URN нажмите Select и выберите ранее созданную функцию авторизации.
-
Нажмите OK.
Custom Authorizer создан.
Теперь нужно настроить авторизацию для функций. access_token будет передаваться с сайта в каждом запросе в заголовке X-Access-Token.
Авторизацию нужно настроить для каждого API: для GET, POST и DELETE. Повторите инструкцию ниже для каждого из методов.
-
В списке сервисов выберите API Gateway.
-
Перейдите в раздел API Publishing → APIs.
-
Напротив нужного метода нажмите Edit.
-
В поле Security Authentication выберите Custom.
-
В поле Custom Authorizer выберите созданный ранее Custom Authorizer.
-
Нажмите Next.
-
Нажмите Add Input Parameter.
-
В поле Name введите X-Access-Token.
-
В поле Location выберите Header.
-
В поле Type выберите String.
-
Нажмите OK.
-
Нажмите Finish.
-
Нажмите Publish API.
-
Нажмите Publish.
Когда для каждого API настроена авторизация, запросы через Postman работать перестанут. Они не будут содержать нужный заголовок. Если же вручную добавить заголовок и задать произвольное значение, API вернет ошибку и никаких действий с базой данных выполнено не будет.
- Создание Keycloak-сервера для аутентификации пользователей
- Аутентификация на сайте
- Аутентификация в API