Защита API с помощью шлюза Apache APISIX API Gateway


Введение

В этом руководстве мы рассмотрим некоторые встроенные плагины Apache APISIX API Gateway для защиты ваших Spring Boot REST API и продемонстрируем, как эффективно их использовать. Вы научитесь запускать мультиконтейнерное приложение (backend, db, apisix и etcd вместе) с помощью Docker compose. В курсе также содержатся концептуальные знания о безопасности API, важной роли шлюза API в решении сквозных проблем, а также о том, как Apache APISIX может помочь вам упростить и ускорить задачу обеспечения безопасности API.

Вот краткое описание того, чем мы занимаемся:

✅ Обзор безопасности API.
✅ Шлюз API в качестве привратника.
✅ Как шлюз APISIX защищает ваши API?
✅ Клонируйте демо-репозиторий apisix-security-java-spring с GitHub.
✅ Разберитесь в структуре проекта и файла docker-compose.yaml.
✅ Постройте многоконтейнерный APISIX с помощью Docker CLI.
✅ Разрешите доступ к вашему API только IP-адресам из белого списка с помощью плагина ограничения IP-адресов.
✅ Блокируйте прямой доступ к некоторым ресурсам API с помощью плагина Uri-blocker.
✅ Убедитесь, что только разрешенные пользователи могут запрашивать ваш API с помощью плагина Consumer restriction.

Ключевые вещи, которые нам нужны:

👉 JDK 11+. Убедитесь, что в вашей системе установлен пакет OpenJDK. Для этой демонстрации я использовал Windows OS и Java 11.
👉 Docker desktop — для выполнения этого руководства вам также понадобится локально установленный Docker desktop. Он доступен для Windows или macOS. Или установите Docker ACI Integration CLI для Linux.

💁 Прежде чем мы начнем, давайте быстро расширим наши теоретические знания о безопасности API и концепциях API Gateway.

Обзор безопасности API

Безопасность API — это термин, относящийся к практике и продуктам, которые предотвращают злонамеренные атаки на интерфейсы прикладных программ (API). Поскольку API стали ключом к программированию веб-интерфейсов, они стали мишенью для хакеров. В результате базовая аутентификация, требующая только имена пользователей и пароли, была заменена различными методами безопасности, такими как многофакторная аутентификация (MFA) или токены, например, веб-токены JWT.

В современную эпоху безопасность API становится все более важной. Существует множество методов усиления безопасности:

  • шифрование TLS
  • брандмауэры API
  • Проверка достоверности данных запроса
  • Дросселирование для защиты
  • Постоянный мониторинг
  • Аудит
  • Ведение журнала
  • Ограничение IP-адресов
  • И многое другое.

Безопасность API с передачей репрезентативного состояния (REST) является одним из наиболее распространенных способов защиты API. Безопасность REST API подразумевает использование унифицированного идентификатора ресурса (URI) протокола передачи гипертекста (HTTP), который контролирует данные, к которым API получает доступ в процессе работы. Таким образом, защита REST API может предотвратить атаки с использованием вредоносных данных, которые злоумышленник пытается внедрить с помощью API.

Шлюз API в качестве привратника👮

Шлюз API — это важный компонент решения для управления API. Он является ключом к безопасности API и защищает базовые данные, как привратник, проверяющий аутентификацию и авторизацию и управляющий трафиком. Являясь тонким слоем между пользовательскими клиентами и вышестоящими сервисами, шлюз API расширяется многочисленными плагинами для обработки аутентификации, авторизации, управления трафиком и безопасности.

Apache APISIX — это легкий API-шлюз с открытым исходным кодом, который находится перед вашими вышестоящими службами. Простой в настройке и быстрый в развертывании API-шлюз APISIX служит центральной точкой для маршрутизации всех входящих запросов по назначению, будь то вышестоящий API-сервер, сторонний сервис, база данных или даже бессерверный.

Как шлюз APISIX защищает ваши API?

Безопасность API в APISIX является наивысшим приоритетом. Поскольку шлюз служит в качестве встроенной прокси-точки контроля над API.

  • Проверяет личность, связанную с запросами API, с помощью проверки учетных данных и токенов, а также других средств аутентификации. Вы можете проверить доступные плагины аутентификации.
  • Определяет, какой трафик разрешено пропускать через API к внутренним службам.
  • Контролирует трафик, проходящий через API, используя ограничение скорости и дросселирование. Для этого существуют плагины контроля трафика.
  • Наблюдает за всеми запросами и применяет политики времени выполнения для обеспечения управления. Существует множество плагинов наблюдаемости, которые можно легко включить для ваших API.
  • Внедряет все стандартные для отрасли шифрования.

Получив достаточно знаний, теперь мы можем начать применять некоторые плагины безопасности в действии для нашего демонстрационного приложения Spring Boot App. Давайте приступим 🚀.

Клонирование демонстрационного репозитория

Для этой демонстрации мы воспользуемся демо-проектом apisix-security-java-spring, который я подготовил заранее. Вы можете посмотреть его на Github.

Используйте git для клонирования репозитория:

git clone 'https://github.com/Boburmirzo/apisix-security-java-spring'
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Перейдите в корневой каталог apisix-security-java-spring

cd apisix-security-java-spring
Войдите в полноэкранный режим Выйти из полноэкранного режима

Вы можете открыть проект в своем любимом редакторе кода. Я использовал IntelliJ Idea community edition. Вы увидите следующую структуру каталогов проекта:

Понять структуру проекта

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

  • Конфигурационные файлы APISIX — Все сервисы настраиваются путем монтирования внешних конфигурационных файлов проекта в docker-контейнеры: /apisix_conf/conf.yaml определяет конфигурации для apisix. Аналогично, конфигурации для etcd, prometheus и grafana находятся в /etcd_conf/etcd.conf.yml, /prometheus_conf/prometheus.yml и /grafana_conf/config соответственно.
  • Журналы APISIX — в папке apisix_log регистрируются запросы APISIX Admin и Control API, такие как access.log или error.log.
  • Проект Spring Boot — Далее в папке spring-postgres хранится Java-приложение с фреймворком Spring (классы Controller, repository и entity) и настройка базы данных PostgreSQL с фиктивной схемой и данными.

  • Файл Docker compose — Файл docker-compose.yml определяет приложение с некоторыми сервисами:

☝️Вы можете заметить, что все сервисы сопоставлены с сетью apisix.

Проект apisix-security-java-spring использует аналогичный пример шаблона APISIX docker compose.

version: "3"

services:
  apisix-dashboard:
    image: apache/apisix-dashboard:2.10.1-alpine
    restart: always
    volumes:
    - ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml
    ports:
    - "9000:9000"
    networks:
      apisix:

  apisix:
    image: apache/apisix:2.13.1-alpine
    restart: always
    volumes:
      - ./apisix_log:/usr/local/apisix/logs
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
    depends_on:
      - etcd
    ##network_mode: host
    ports:
      - "9080:9080/tcp"
      - "9091:9091/tcp"
      - "9443:9443/tcp"
      - "9092:9092/tcp"
    networks:
      apisix:

  etcd:
    image: bitnami/etcd:3.4.15
    restart: always
    volumes:
      - etcd_data:/bitnami/etcd
    environment:
      ETCD_ENABLE_V2: "true"
      ALLOW_NONE_AUTHENTICATION: "yes"
      ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2379"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
    ports:
      - "12379:2379/tcp"
    networks:
      apisix:

  prometheus:
    image: prom/prometheus:v2.25.0
    restart: always
    volumes:
      - ./prometheus_conf/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
      apisix:

  grafana:
    image: grafana/grafana:7.3.7
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - "./grafana_conf/provisioning:/etc/grafana/provisioning"
      - "./grafana_conf/dashboards:/var/lib/grafana/dashboards"
      - "./grafana_conf/config/grafana.ini:/etc/grafana/grafana.ini"
    networks:
      apisix:

  backend:
    build: spring-postgres/backend
    ports:
      - "8080:8080"
    environment:
      - POSTGRES_DB=example
    networks:
      apisix:

  db:
    image: postgres
    restart: always
    secrets:
      - db-password
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      apisix:
    environment:
      - POSTGRES_DB=example
      - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
    expose:
      - 5432
networks:
  apisix:
    driver: bridge
secrets:
  db-password:
    file: spring-postgres/db/password.txt
volumes:
  db-data:
  etcd_data:
    driver: local
Вход в полноэкранный режим Выход из полноэкранного режима

Сборка многоконтейнерного APISIX с помощью Docker CLI

Теперь мы можем запустить наше приложение, выполнив команду docker compose из корневой папки проекта:

docker-compose -p docker-apisix up -d
Войти в полноэкранный режим Выйти из полноэкранного режима

Пример вывода:


Вход в полноэкранный режим Выход из полноэкранного режима

Список запущенных контейнеров можно увидеть, выполнив команду docker compose ps CLI или используя docker desktop:

Когда контейнеры запущены, перейдите по адресу http://localhost:8080/get в веб-браузере и вы увидите следующий результат:

Этот ответ на самом деле приходит от простого Spring Boot REST API. Если вы посмотрите папку проекта spring-postgres, каталог src/main/java содержит исходный код нашего проекта. Есть класс контроллера GreetingController, аннотированный @RestController, где одна конечная точка /get обслуживает наши запросы. По сути, он извлекает данные из базы данных PostgreSQL и отвечает на запрос атрибутом name в классе сущности Greeting.

На следующих шагах мы включим различные плагины безопасности Apache APISIX для этой конечной точки.

@RestController
public class GreetingController {

    private final GreetingRepository repository;

    public GreetingController(GreetingRepository repository) {
        this.repository = repository;
    }

    @GetMapping("/get")
    public String getApisixGreeting() {
        Greeting apisixGreeting = repository.findById(1).orElse(new Greeting("Not Found 😕"));
        return apisixGreeting.getName();
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Включение ограничения IP-адресов

Теперь мы можем включить плагин ограничения IP-адресов для конечной точки API. IP-ограничение — это метод ограничения IP-адресов клиентов, которые могут отправлять запросы, путем составления белого/черного списка IP-адресов. Мы не можем получить доступ к API с IP-адресов, отличных от разрешенных.

На первом этапе нам нужно создать восходящий поток для нашего бэкенд-сервиса. Мы используем команды curl для взаимодействия с API администратора APISIX:

curl "http://127.0.0.1:9080/apisix/admin/upstreams/1" -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -X PUT -d '
{
  "type": "roundrobin",
  "nodes": {
    "backend:8080": 1
  }
}'
Войти в полноэкранный режим Выйти из полноэкранного режима

Объект Upstream будет указывать на целевой сервис backend или несколько сервисов backend, в нашем случае он ссылается на Spring Boot REST API.

На следующем этапе мы определяем маршрут и привязываем его к Upstream. Он может быть привязан по upstream_id в конкретном маршруте. Также мы включим плагин ip-restriction в конфигурации маршрута.

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/get",
    "plugins": {
       "ip-restriction": {
            "whitelist": [
                "127.0.0.2"
            ]
        }
    },
    "upstream_id": "1"
}'
Вход в полноэкранный режим Выход из полноэкранного режима

В атрибуте whitelist плагина ip-restriction мы разрешаем доступ к /get URI только одному IP-адресу 127.0.0.2. Если вы попытаетесь получить доступ к API с запрещенным IP-адресом, APISIX выдаст ошибку 403 Forbidden Http:

curl http://127.0.0.1:9080/get -i --interface 127.0.0.1
Вход в полноэкранный режим Выход из полноэкранного режима

Пример вывода:

HTTP/1.1 403 Forbidden
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.13.1

{"message":"Your IP address is not allowed"}
Вход в полноэкранный режим Выход из полноэкранного режима

☝️ В конфигурации плагина можно использовать один IP, несколько IP или диапазоны в нотации CIDR, например 10.10.10.0/24. Плагин также поддерживает адреса IPv4 и IPv6.

Теперь мы знаем один способ защиты наших API путем разрешения/запрета IP-адресов с помощью APISIX.

Блокирование прямого доступа к ресурсу API

Далее рассмотрим более расширенные возможности блокировки URI с помощью плагина uri-blocker путем применения правил фильтрации regex. Например, у нас может быть сценарий, когда конечная точка API должна быть заблокирована, если пользователь пытается получить доступ и загрузить приватный файл sample-file.csv.

Мы можем включить плагин uri-blocker аналогично настройке плагина ip-restriction, которую мы применили в предыдущем шаге:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/*",
    "plugins": {
       "uri-blocker": {
          "block_rules": ["sample-file.csv+"]
        }
    },
    "upstream_id": "1"
}'
Вход в полноэкранный режим Выход из полноэкранного режима

После того, как вы настроили плагин, как показано выше, вы можете попробовать получить доступ к файлу с помощью команды curl:

curl -i http://127.0.0.1:9080/sample-file.csv
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы должны получить еще одну ошибку Http 403 Forbidden:

HTTP/1.1 403 Forbidden
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь мы ограничили прямой доступ к ресурсу URI. Вы также можете установить свойство rejected_msg в конфигурации плагина, чтобы настроить сообщение тела ответа.

Разрешить пользователям запрашивать API

Одна из техник — сделать соответствующие ограничения доступа к ресурсам API для определенных пользователей или сервисов. Ограничение потребителя (consumer-restriction) — делает соответствующие ограничения доступа к вашим сервисам или маршрутам на основе различных выбранных пользователей. Если неизвестный пользователь попытается отправить запрос, Apache APISIX встретит его ошибкой.

Предположим, что у нас есть два потребителя наших API (consumer1 и consumer2). Мы хотим предоставить доступ только одному из них. Для этого давайте создадим двух потребителей и включим плагин consumer-restriction для нашего существующего примера маршрута.

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

curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
    "username": "consumer1",
    "plugins": {
        "basic-auth": {
            "username":"consumer1",
            "password": "123456"
        }
    }
}'
Войти в полноэкранный режим Выйти из полноэкранного режима

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

curl http://127.0.0.1:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
    "username": "consumer2",
    "plugins": {
        "basic-auth": {
            "username":"consumer2",
            "password": "654321"
        }
    }
}'
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем включите плагин consumer-restriction и разрешите только consumer1 доступ к конечной точке /get:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "uri": "/get",
    "plugins": {
        "basic-auth": {},
        "consumer-restriction": {
            "whitelist": [
                "consumer1"
            ]
        }
    },
    "upstream_id": "1"
}'
Войти в полноэкранный режим Выход из полноэкранного режима

У consumer-restriction есть свойство type, которое является перечислимым типом (поддерживает следующие значения: consumer_name, service_id и route_id), мы можем указать его, чтобы разрешить доступ к соответствующему объекту.

По умолчанию плагин возвращает общее сообщение {"message": "Имя_потребителя_запрещено."}, если объект не разрешен. Можно настроить более дружественное сообщение через атрибут плагина.

Теперь мы можем проверить, может ли потребитель consumer1 запросить ресурс API с предоставленными учетными данными:

curl -u consumer1:123456 http://127.0.0.1:9080/get -i
Вход в полноэкранный режим Выход из полноэкранного режима

Выход:

HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 19
Connection: keep-alive
Server: APISIX/2.13.1

Hello Apache APISIX
Войти в полноэкранный режим Выход из полноэкранного режима

Очевидно, что consumer1 может запросить конечную точку, поскольку мы внесли его в белый список в конфигурации плагина consumer-restriction.

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

curl -u consumer2:123456 http://127.0.0.1:9080/get -i
Войти в полноэкранный режим Выйти из полноэкранного режима

Выход:

HTTP/1.1 403 Forbidden
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.13.1

{"message":"The consumer_name is forbidden."}
Войти в полноэкранный режим Выход из полноэкранного режима

Что дальше

В этой статье блога мы показали, как развернуть наше приложение Spring Boot REST API вместе с Apache APISIX API Gateway, используя возможность Docker compose для более плавного развертывания. Кроме того, мы научились использовать базовые плагины безопасности, поэтому вы можете ознакомиться с другими доступными плагинами для удовлетворения более сложных сценариев безопасности API или создать свой собственный плагин для API Gateway с помощью Java Plugin Runner.

Рекомендуемый контент

➔ Смотреть видеоурок Начало работы с Apache APISIX

➔ Прочитать статью в блоге Обзор плагинов для шлюза API Apache APISIX

➔ Читайте статью в блоге Централизованная аутентификация с помощью плагинов Apache APISIX

➔ Читайте запись в блоге Безопасность API с OIDC с помощью Apache APISIX и Microsoft Azure AD

➔ Читайте запись в блоге Наблюдаемость API с помощью плагинов Apache APISIX.

Сообщество⤵️

🙋 Присоединяйтесь к сообществу Apache APISIX
🐦 Следите за нами в Twitter
📝 Найдите нас в Slack
📧 Пишите нам со своими вопросами

Оцените статью
Procodings.ru
Добавить комментарий