«1. Обзор

В этом руководстве мы представим проект Spring Cloud Open Service Broker и узнаем, как реализовать API Open Service Broker.

Сначала мы углубимся в спецификацию Open Service Broker API. Затем мы узнаем, как использовать Spring Cloud Open Service Broker для создания приложений, реализующих спецификации API.

Наконец, мы рассмотрим, какие механизмы безопасности мы можем использовать для защиты конечных точек нашего сервис-брокера.

2. Open Service Broker API

Проект Open Service Broker API позволяет нам быстро предоставлять услуги поддержки для наших приложений, работающих на облачных платформах, таких как Cloud Foundry и Kubernetes. По сути, спецификация API описывает набор конечных точек REST, через которые мы можем предоставлять эти услуги и подключаться к ним.

В частности, мы можем использовать сервис-брокеров на облачной платформе для:

    Объявления каталога резервных служб Предоставления экземпляров службы Создания и удаления привязок между резервной службой и клиентским приложением Отзыва экземпляров службы

Spring Cloud Open Service Broker создает основу для реализации, совместимой с API Open Service Broker, предоставляя необходимые веб-контроллеры, объекты домена и конфигурацию. Кроме того, нам нужно будет придумать нашу бизнес-логику, реализовав соответствующие интерфейсы сервисного брокера.

3. Автоматическая настройка

Чтобы использовать Spring Cloud Open Service Broker в нашем приложении, нам нужно добавить соответствующий начальный артефакт. Мы можем использовать Maven Central для поиска последней версии стартера open-service-broker.

Помимо облачного стартера, нам также потребуется включить веб-стартер Spring Boot, а также Spring WebFlux или Spring MVC, чтобы активировать автоконфигурацию:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-open-service-broker</artifactId>
    <version>3.1.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Механизм автоконфигурации настраивает реализации по умолчанию для большинства компонентов, которые нам нужны для сервисного брокера. Если мы хотим, мы можем переопределить поведение по умолчанию, предоставив нашу собственную реализацию bean-компонентов open-service-broker, связанных со Spring.

3.1. Конфигурация пути конечных точек компонента Service Broker

По умолчанию путь контекста, в котором зарегистрированы конечные точки компонента Service Broker, имеет вид «/».

Если это не идеально и мы хотим его изменить, самый простой способ — установить свойство spring.cloud.openservicebroker.base-path в свойствах нашего приложения или файле YAML:

spring:
  cloud:
    openservicebroker:
      base-path: /broker

В этом случае, чтобы запросить конечные точки сервисного брокера, нам сначала нужно добавить к нашим запросам префикс /broker/ base-path.

4. Пример Service Broker

Давайте создадим приложение Service Broker, используя библиотеку Spring Cloud Open Service Broker, и рассмотрим, как работает API.

В нашем примере мы будем использовать сервис-брокер для предоставления и подключения к резервной почтовой системе. Для простоты мы будем использовать фиктивный почтовый API, представленный в наших примерах кода.

4.1. Каталог услуг

Во-первых, чтобы контролировать, какие услуги предлагает наш брокер услуг, нам нужно определить каталог услуг. Чтобы быстро инициализировать каталог сервисов, в нашем примере мы предоставим bean-компонент Spring типа Catalog:

@Bean
public Catalog catalog() {
    Plan mailFreePlan = Plan.builder()
        .id("fd81196c-a414-43e5-bd81-1dbb082a3c55")
        .name("mail-free-plan")
        .description("Mail Service Free Plan")
        .free(true)
        .build();

    ServiceDefinition serviceDefinition = ServiceDefinition.builder()
        .id("b92c0ca7-c162-4029-b567-0d92978c0a97")
        .name("mail-service")
        .description("Mail Service")
        .bindable(true)
        .tags("mail", "service")
        .plans(mailFreePlan)
        .build();

    return Catalog.builder()
        .serviceDefinitions(serviceDefinition)
        .build();
}

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

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

В конце концов, каталог служб становится доступным для облачных платформ через конечную точку сервисного брокера /v2/catalog:

curl http://localhost:8080/broker/v2/catalog

{
    "services": [
        {
            "bindable": true,
            "description": "Mail Service",
            "id": "b92c0ca7-c162-4029-b567-0d92978c0a97",
            "name": "mail-service",
            "plans": [
                {
                    "description": "Mail Service Free Plan",
                    "free": true,
                    "id": "fd81196c-a414-43e5-bd81-1dbb082a3c55",
                    "name": "mail-free-plan"
                }
            ],
            "tags": [
                "mail",
                "service"
            ]
        }
    ]
}

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

4.2. Предоставление услуг

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

Кроме того, то, что представляет собой подготовка, зависит от брокера. В некоторых случаях подготовка может включать развертывание пустых баз данных, создание брокера сообщений или просто предоставление учетной записи для доступа к внешним API.

С точки зрения терминологии службы, созданные сервис-брокером, будут называться экземплярами службы.

С помощью Spring Cloud Open Service Broker мы можем управлять жизненным циклом службы, реализуя интерфейс ServiceInstanceService. Например, чтобы управлять запросами на предоставление службы в нашем брокере служб, мы должны предоставить реализацию метода createServiceInstance:

@Override
public Mono<CreateServiceInstanceResponse> createServiceInstance(
    CreateServiceInstanceRequest request) {
    return Mono.just(request.getServiceInstanceId())
        .flatMap(instanceId -> Mono.just(CreateServiceInstanceResponse.builder())
            .flatMap(responseBuilder -> mailService.serviceInstanceExists(instanceId)
                .flatMap(exists -> {
                    if (exists) {
                        return mailService.getServiceInstance(instanceId)
                            .flatMap(mailServiceInstance -> Mono.just(responseBuilder
                                .instanceExisted(true)
                                .dashboardUrl(mailServiceInstance.getDashboardUrl())
                                .build()));
                    } else {
                        return mailService.createServiceInstance(
                            instanceId, request.getServiceDefinitionId(), request.getPlanId())
                            .flatMap(mailServiceInstance -> Mono.just(responseBuilder
                                .instanceExisted(false)
                                .dashboardUrl(mailServiceInstance.getDashboardUrl())
                                .build()));
                    }
                })));
}

Здесь мы выделяем новую почтовую службу в наших внутренних сопоставлениях, если она имеет тот же идентификатор экземпляра службы. не существует, и укажите URL панели мониторинга. Мы можем рассматривать панель мониторинга как веб-интерфейс управления для нашего экземпляра службы.

Предоставление службы доступно для облачных платформ через конечную точку /v2/service_instances/{instance_id}:

curl -X PUT http://localhost:8080/broker/v2/service_instances/[email protected] 
  -H 'Content-Type: application/json' 
  -d '{
    "service_id": "b92c0ca7-c162-4029-b567-0d92978c0a97", 
    "plan_id": "fd81196c-a414-43e5-bd81-1dbb082a3c55"
  }' 

{"dashboard_url":"http://localhost:8080/mail-dashboard/[email protected]"}

Короче говоря, когда мы предоставляем новую услугу, нам нужно передать service_id и plan_id рекламируется в каталоге услуг. Кроме того, нам необходимо предоставить уникальный instance_id, который наш сервисный брокер будет использовать в будущих запросах на привязку и отмену подготовки.

4.3. Связывание службы

После предоставления службы нам нужно, чтобы наше клиентское приложение начало с ней взаимодействовать. С точки зрения брокера служб это называется привязкой службы.

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

В нашем примере, если в рекламируемом сервисе для поля bindable установлено значение true, наш брокер сервисов должен предоставить реализацию интерфейса ServiceInstanceBindingService. В противном случае облачные платформы не будут вызывать методы привязки службы из нашего брокера служб.

Давайте обработаем запросы на создание привязки службы, предоставив реализацию метода createServiceInstanceBinding:

@Override
public Mono<CreateServiceInstanceBindingResponse> createServiceInstanceBinding(
    CreateServiceInstanceBindingRequest request) {
    return Mono.just(CreateServiceInstanceAppBindingResponse.builder())
        .flatMap(responseBuilder -> mailService.serviceBindingExists(
            request.getServiceInstanceId(), request.getBindingId())
            .flatMap(exists -> {
                if (exists) {
                    return mailService.getServiceBinding(
                        request.getServiceInstanceId(), request.getBindingId())
                        .flatMap(serviceBinding -> Mono.just(responseBuilder
                            .bindingExisted(true)
                            .credentials(serviceBinding.getCredentials())
                            .build()));
                } else {
                    return mailService.createServiceBinding(
                        request.getServiceInstanceId(), request.getBindingId())
                        .switchIfEmpty(Mono.error(
                            new ServiceInstanceDoesNotExistException(
                                request.getServiceInstanceId())))
                        .flatMap(mailServiceBinding -> Mono.just(responseBuilder
                            .bindingExisted(false)
                            .credentials(mailServiceBinding.getCredentials())
                            .build()));
                }
            }));
}

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


Платформа Spring Cloud Open Service Broker предоставляет операции привязки службы через конечную точку /v2/service_instances/{instance_id}/service_bindings/{binding_id}:

curl -X PUT 
  http://localhost:8080/broker/v2/service_instances/[email protected]/service_bindings/admin 
  -H 'Content-Type: application/json' 
  -d '{ 
    "service_id": "b92c0ca7-c162-4029-b567-0d92978c0a97", 
    "plan_id": "fd81196c-a414-43e5-bd81-1dbb082a3c55" 
  }'

{
    "credentials": {
        "password": "bea65996-3871-4319-a6bb-a75df06c2a4d",
        "uri": "http://localhost:8080/mail-system/[email protected]",
        "username": "admin"
    }
}

Как и при подготовке экземпляра службы, мы используем service_id и plan_id, объявленный в каталоге услуг в рамках нашего запроса на привязку. Кроме того, мы также передаем уникальный binding_id, который брокер использует в качестве имени пользователя для нашего набора учетных данных.

5. Безопасность API сервис-брокера

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

К сожалению, спецификация Open Service Broker API в настоящее время не охватывает часть аутентификации для конечных точек сервисного брокера. Из-за этого библиотека Spring Cloud Open Service Broker не реализует никакой конфигурации безопасности.

К счастью, если нам нужно защитить конечные точки нашего сервис-брокера, мы можем быстро использовать Spring Security для реализации базовой аутентификации или механизма OAuth 2.0. В этом случае мы должны аутентифицировать все запросы сервис-брокера, используя выбранный нами механизм аутентификации, и возвращать ответ 401 Unauthorized, если аутентификация не удалась.

6. Заключение

В этой статье мы рассмотрели проект Spring Cloud Open Service Broker.

«Во-первых, мы узнали, что такое Open Service Broker API и как он позволяет нам предоставлять резервные службы и подключаться к ним. Впоследствии мы увидели, как быстро создать проект, совместимый с API Service Broker, с помощью библиотеки Spring Cloud Open Service Broker.

Наконец, мы обсудили, как мы можем защитить конечные точки нашего сервисного брокера с помощью Spring Security.


Как всегда, исходный код этого руководства доступен на GitHub.