Подавляющее большинство статей и тематических исследований, которые я прочитал за эти годы, нацелено на очень крупный корпоративный рынок. В то время как многие из идей являются обоснованными, большая инфраструктура, часто необходимая для этих решений, может быть излишней для проекта развертывания малого и среднего размера, где ожидаемый размер развертывания находится в диапазоне от нескольких сотен клиентов, а не от десятков или сотен тысяч. Это исследование посвящено тому, как наша организация смогла создать эффективное, масштабируемое SOA-решение, которое не перегружало бы наш персонал по разработке или эксплуатации. Но прежде чем углубляться в детали, позвольте мне отвлечься на несколько параграфов, чтобы дать представление о конкретных проблемах, с которыми мы столкнулись.
Фон
Digital Solutions, Inc. (DSI) специализируется на предоставлении программных и технологических решений для индустрии исправлений. В первую очередь это означает, что программное обеспечение для управления записями контролирует население исправительного учреждения. Система управления правонарушителями (OMS) регистрирует повседневную жизнь заключенных с момента их бронирования до момента их освобождения. В течение многих лет наша система претерпела множество изменений, начиная с приложения для DOS, написанного с использованием Clipper, и с использованием dBase. В эпоху Windows наше программное обеспечение стало приложением Win 32, подключающимся к базе данных сервера Oracle или MS SQL. И, наконец, в своем нынешнем воплощении это n-уровневое приложение на основе Java с веб-интерфейсом и поддержкой нескольких источников данных на сервере.
Большая часть приложения OMS посвящена финансам заключенных. Большинство исправительных учреждений в США предоставляют заключенным возможность иметь личный трастовый счет для их исключительного использования, находясь в заключении. Деньги на этом счете могут быть использованы для оплаты штрафов и судебных издержек, покупки предметов у комиссара или покупки времени в телефонной сети заключенного учреждения. DSI имеет дочернюю компанию Inmate Telephone, Inc (ITI), которая предоставляет услуги телефонной связи для заключенных во многих учреждениях, где установлено наше программное обеспечение OMS. DSI / ITI создали собственное приложение для выставления счетов, которое обрабатывало переводы из распределенных мест заключения или тюрьмы (через коммутируемое соединение), а также позволяло нам принимать платежи по счетам через наш колл-центр.Наши операторы в режиме реального времени принимают вызов и вручную вводят номера кредитных карт в стандартную торговую клавиатуру. Процесс занимал очень много времени до середины 2003 года, когда мы разработали наш первый сервис для обслуживания кредитных карт. Примерно через 2 года мы выпустили веб-сайт, который позволял пользователям управлять своей учетной записью в Интернете.
Поскольку DSI / ITI уже имел опыт разработки систем телефонии, мы решили написать систему IVR, чтобы вывести из строя как можно больше операторов, а также позволить нашим клиентам проверять баланс и осуществлять платежи 24/7. Основная идея SOA — не дублировать сервисы, поэтому мы решили представить некоторые функциональные возможности веб-сайта в виде отдельных облегченных веб-сервисов и называть эти веб-сервисы из приложения телефонии.
Архитектура развертывания
Веб-сайт развернут на избыточных экземплярах JBoss 4.2 и оснащен веб-сервером Apache 2.0, который выполняет балансировку нагрузки. Веб-сервер и блейд-серверы JBoss работают под управлением Windows Server. Блейд-серверы JBoss защищены межсетевым экраном, который обеспечивает сетевой доступ только к нашим внутренним базам данных Oracle и доступ к совершенно отдельному сегменту сети, где хранится наша служба обработки кредитных карт.
Сайт ITI никогда не был написан с учетом будущей интеграции. Для приложения мы использовали проприетарную веб-инфраструктуру, которую лучше всего объяснить как нечто среднее между Struts и Spring Webflow, хотя ни один из проектов фактически не использовался для создания или проектирования нашей платформы. Но поскольку было строго установлено разделение между бизнес-логикой и уровнем представления, было нетрудно добавить новый тип представления для интеграции. Концепция «действия» является центральной в том, как работает наша платформа. Действие может рассматриваться как отдельное действие работы, например, «Вход в систему», «Выход из системы», «Внести платеж» и т. Д. Какие действия доступны для выполнения в любой момент времени, регулируются предыдущими действиями, выполненными сеансом пользователя. предоставляя последнюю линию защиты безопасности,поскольку единственный способ сделать действия доступными для выполнения — это найти подходящие пути вплоть до этой точки.
В веб-приложении путь пользователя довольно легко смоделировать таким способом. Если пользователь нажимает на кнопку «Войти», проверьте учетные данные, а затем предоставьте пользователю экран, отображающий различные области приложения, к которым они могут перейти. Оказавшись там, пользователь может перейти в раздел «Заявления», либо в раздел «Выполнить платеж», либо в «Профиль аккаунта». В зависимости от взаимодействия с пользователем внутреннее состояние веб-приложения изменяется, отражая новые действия, доступные пользователю. Эта обработка аналогична контроллеру в среде MVC.
Переход к сервис-ориентированной архитектуре
Адаптировать эту платформу к модели веб-сервиса было довольно просто; однако с веб-службами нет состояния, поэтому мы упростили модель действий, удалив иерархию доступных действий. А поскольку ожидаемое развертывание этого веб-сервиса ограничивалось нашими собственными приложениями, мы решили отказаться от сложных стандартов, таких как SOAP. Проще говоря, мы собирались имитировать то, что происходит, когда пользователь нажимает на ссылку или отправляет форму в нашем приложении. Вместо того, чтобы возвращать обратно страницу в кодировке HTML, мы бы использовали простой XML без проверки dtd или схемы.
Безопасность
Этот подход открыл еще одну червь в отношении безопасности. Побочным эффектом выравнивания иерархии действий будет то, что команда «Внести депозит» будет доступна без входа в систему. Несмотря на то, что для внесения депозита требовалась кредитная карта, мы все равно не хотели, чтобы люди обошли страницу входа в систему. Никогда не стоит недооценивать желание людей обманывать систему!
Один из ответов на эту проблему безопасности оказался довольно простым из-за того, как было разработано и развернуто приложение. Поскольку мы использовали действие, отправленное как часть набора параметров, была только одна конечная точка сервлета, с которой нужно было бороться. Исходя из наших вариантов использования, не было необходимости в дальнейшей детализации прав; то есть, если бы вы могли получить доступ к сервлету, вы могли бы выполнить любое из действий. Легким ответом было просто настроить сервер Apache, который выполнял роль нашего балансировщика нагрузки, чтобы разрешать запросы только этому конкретному сервлету из нашего локального домена. Мы добавили директиву местоположения в нашей конфигурации виртуального хоста, чтобы выполнить это довольно легко:
<Location /servletName >
Order Deny,Allow
Allow from 172.22.0.0/16
Allow from 192.168.0.0/8
Deny from All
</Location>
Эта конфигурация работала нормально для нас, пока потребность в новом продукте не выдвинула требования веб-сервисов за пределы нашей локальной сети.
Распределенная синхронизация данных
Новый продукт был предназначен для банковских заключенных. В частности, представители широкой общественности могут вносить деньги на счет заключенного через веб-сайт или через киоск в вестибюле учреждения. Мы столкнулись с множеством препятствий, создавая это. Первым был тот факт, что каждое учреждение имело свою базу данных заключенных локально, и не было ни центрального хранилища данных, ни общей сети. Многие из этих средств распределены по всей стране, и большинство даже не в сети штата или округа. Поскольку не было никакого способа обосновать необходимость предоставления частных сетей этим объектам, нам пришлось полагаться на Интернет через легкодоступные и недорогие DSL и кабельные каналы.
Многие из особенностей, касающихся синхронизации между объектом и нашим центром обработки данных, были отложены на более поздний этап процесса, но мы знали, что 1) данные заключенных будут каким-то образом заполнены в нашей базе данных, и 2) мы будем экспортировать платежи. сделано для заключенного в определенном учреждении как-то. Таким образом, мы с радостью приступили к созданию нашего приложения в той же модели, что и система депозитного телефона для заключенных. Мы использовали Apache во внешнем интерфейсе нескольких экземпляров JBoss, работающих на нескольких блейдах. Mod-JK и протокол AJP использовались между Apache и блейдами, как и прежде.
Как только мы завершили существенную разработку веб-сайта, мы снова обратили наше внимание на синхронизацию данных и обслуживание. Опять же, мы сгладили модель действия, выставив один сервлет, который мог реагировать на любые действия. Для этого случая у нас было всего три действия. Один для добавления / редактирования заключенного, один для получения неперечисленных депозитов и третий для изменения статуса депозита на переведенный. Этого было бы достаточно для синхронизации заключенных и перемещения депозитов, но мы также хотели иметь возможность делать депозит удаленно. Одновременно мы разработали устройство для киосков, которое может принимать наличные и кредитные карты для внесения депозита. Устройства были относительно тупыми, и ожидалось, что они получат все соответствующие данные из удаленного источника, поскольку у них не было внутренней базы данных.Для этой услуги у нас были такие действия, как «Поиск заключенных», «Получение информации о заключенных», «Проверка кредитной карты» и «Сделать депозит». В истинном стиле SOA вся бизнес-логика содержалась в одной точке нашего предприятия, на сайте InmateBanker.
Мы объединили наш список действий и приступили к написанию бизнес-логики в нашем приложении для обработки всех этих действий. Одним из не менее значительных преимуществ таких веб-сервисов без сохранения состояния является тестирование. Мы могли ускорить процесс разработки и модульного тестирования, поскольку каждое действие не зависело от других. А поскольку мы по сути имитировали браузер, мы могли бы выполнить специальное тестирование, просто введя URL-адрес в нашем браузере и просмотрев полученный XML.
Безопасность с EJBCA
Мы включили информацию аутентификации в список параметров, предпочитая, чтобы транспортный уровень выполнял авторизацию, как мы делали с нашим внутренним веб-сервисом. Разница была в том, что мы не могли просто полагаться на IP-адреса клиентов. Мы отказались от идеи ведения списка IP-адресов наших клиентов, быстро поняв, что это будет проблемой технического обслуживания в долгосрочной перспективе, поскольку некоторые из наших небольших клиентов могут работать по динамической адресации, назначенной их провайдером. Кроме того, поскольку мы будем пропускать любой запрос с этого IP-адреса, мы, по сути, будем открывать любой компьютер в этой локальной сети для веб-службы.
Мы обратились к использованию SSL с аутентификацией клиента. Это было идеально подходит. На нашем сервере Apache уже был скомпилирован OpenSSL, и у нас уже были настроены виртуальные хосты и соответствующие директивы расположения в нем. Требовать сертификат клиента было так же просто, как добавить эту директиву местоположения в наш виртуальный хост с поддержкой SSL:
<Location /servletName>
SSLVerifyClient require
</Location>
Эта простая директива означала, что для доступа к ресурсу мы должны сначала предоставить действительный сертификат клиента. Мы не хотели поддерживать белый список разрешенных сертификатов, и при этом мы не хотели платить комиссию лицензирующему органу за каждую лицензию, которую мы развертываем на местах. Решением было использование нашего собственного центра сертификации (CA). К счастью, фантастический инструмент с открытым исходным кодом, EJBCA, уже завершил тяжелую работу для нас. Мы развернули EJBCA в нашей локальной сети и приступили к созданию двух разных центров сертификации: один для телефонной линии для заключенных нашего бизнеса и один для банковской системы для заключенных.
Мы добавили директивы в наш виртуальный хост, чтобы указать ключи для CA, которые мы собираемся принять для аутентификации клиента. Мы также указали директиву для Списка отзыва сертификатов, которую EJBCA может создать и управлять для нас:
SSLCACertificateFile conf/ssl/InmateTelephoneCA.crt
SSLCARevocationFile conf/ssl/InmateTelephoneCA.crl
CRL особенно интересен, потому что он дал нам возможность мгновенно отозвать сертификат, если машина киоска должна была быть физически взломана.
После того, как мы создали CA в EJBCA, мы могли начать выпускать сертификаты из него. Каждый киоск, который был потребителем двух отдельных услуг, получил два сертификата, по одному для каждой стороны бизнеса. Люди могли положить деньги на свой телефонный счет или на счет заключенного из одного приложения в киоске. Третий сертификат был необходим для службы, которая синхронизировала базу данных на объекте с нашей базой данных в домашнем офисе. Это приложение было создано как дополнительное приложение, которое запускалось в другом месте локальной сети учреждения.
Приложение EJBCA, по сути, имело две стороны. Один был для администрирования и создания сертификатов, а другой — для загрузки сертификатов в браузеры, файлы и загрузки через URL. Мы раскрыли только «публичную» внешнюю сторону EJBCA за пределами нашего брандмауэра, оставив административный компонент в границах нашей локальной сети. Наша причина была в том, чтобы распределенные приложения могли выполнять как можно больше работы по обработке своих собственных сертификатов.
И киоск, и наша часть синхронизации (внутренне называемая IEngine) были написаны на Java и использовали проект HttpClient для большинства компонентов веб-коммуникаций. HttpClient не имеет встроенной поддержки клиентских сертификатов, однако авторы были достаточно хороши, чтобы предоставить эталонные образцы, которые работают практически из коробки, AuthSSLProtocolSocketFactory.java и AuthSSLX509TrustManager.java. Мы написали класс-оболочку, который использовал эти классы вместе с классом протокола HttpClient.
Наша Java выглядела так в нашем вспомогательном классе:
/*First two parameters are for client-authentication, second two parameters are for server-authentication*/
AuthSSLProtocolSocketFactory ssl = new AuthSSLProtocolSocketFactory(
this.clientCertificate, this.clientPassword,
this.serverCertificate, this.serverPassword);
Protocol authhttps = new Protocol("https",
(ProtocolSocketFactory)ssl, 443);
/*Build the actual client and try to connect*/
HttpClient client = new HttpClient();
client.getHostConfiguration().setHost(targetURL.getHost(),
targetURL.getPort(),authhttps);
Затем код перешел к использованию объекта клиента, как обычно. Мы создали объект GetMethod на основе удаленно развернутого имени сервера и использовали массив NameValuePair для передачи параметров.
После того, как запрос был отправлен, код ответа был изучен. Ответ 200 означал, что все было хорошо, и ответ можно передать приложению для обработки. Это не обязательно означает, что фактическое содержание запроса является действительным, только то, что сервер и клиент обрабатывают все в соответствии с инструкциями.
Если был возвращен запрещенный код состояния 403, это означало, что Apache отклонил наш сертификат. Мы ожидали, что наиболее распространенной причиной этого был аннулированный сертификат; однако после развертывания производства мы узнали, что это что-то другое, я вернусь к этому чуть позже.
Получение запрещенного кода приведет к тому, что приложение увидит, был ли выдан новый сертификат для этого конкретного клиента. Каждому устройству был присвоен определенный идентификатор, и он использовал этот идентификатор для вызова веб-службы EJBCA, чтобы попытаться загрузить новый сертификат. Если для этого клиента доступен новый сертификат, он сохраняется на диске, перезаписывая предыдущий. В противном случае, человеку, использующему киоск, выдается ошибка из-за отсутствия обслуживания, и киоск больше не может нормально функционировать. Поскольку EJBCA позволяет загружать сертификат только один раз, нашему операционному персоналу требуется ручное вмешательство для повторной выдачи сертификата. Но как только он будет переиздан, клиент автоматически загрузит и сохранит его. Наличие ручного вмешательства для переиздания является критическим шагом в безопасности,как это ненормальное поведение и действительно должно быть исследовано.
Опасности кеширования
Возвращаясь к ошибке 403, мы быстро поняли, что это не вызвано отказанным сертификатом — это было связано с настройкой кэша в Apache. Apache может использовать внутренний кеш для ускорения обработки SSL. Директива SSLSessionCache контролирует, как это выполняется. Допустимые параметры: кэш в памяти, кэш на диске и ни один. В документации Apache говорится, что эти кэши используются для ускорения параллельных запросов от клиента. Однако есть несколько задокументированных проблем, связанных с использованием кэшей с клиентскими сертификатами, о чем свидетельствует поиск в Google. Проблема ушла, когда мы изменили директиву не кэшировать. В документации Apache говорится, что это приводит к заметному снижению производительности. Однако я бы предпочел, чтобы код работал правильно, а не быстрее!Проблема может проявиться, если Apache откажется от этапа установления связи. Приложение Java, работающее на стороне клиента, может запутаться еще больше, и только перезапуск приложения Java излечит его. Я никогда не отслеживал это до такой степени, что я мог бы сузить, была ли одна сторона инициатором повреждения, так как перезапуск приложения Java вызвал пустой список на стороне Java, а также новое соединение и сеанс в Apache. Все, что я знаю, это то, что устранение SSLSessionCache заставило мои проблемы уйти, и это хорошо.так как перезапуск приложения Java вызвал пустой список на стороне Java, а также новое соединение и сеанс в Apache. Все, что я знаю, это то, что устранение SSLSessionCache заставило мои проблемы уйти, и это хорошо.так как перезапуск приложения Java вызвал пустой список на стороне Java, а также новое соединение и сеанс в Apache. Все, что я знаю, это то, что устранение SSLSessionCache заставило мои проблемы уйти, и это хорошо.
Архитектурный Обзор
Позвольте мне сделать еще одну диаграмму и подытожить то, что мы смогли сделать без особых трудностей и довольно быстро с командой разработчиков, ограниченных во времени и ресурсах.
Ключом ко всей нашей инфраструктуре является разумное использование веб-сервера Apache. Apache обеспечивает безопасность на переднем крае, защищая ресурсы за его счет, используя комбинацию правил контроля доступа и клиентских сертификатов. В то же время Apache служит интерфейсом для двух независимых сайтов электронной коммерции, открытых для широкой публики. И хотя Apache является единственной точкой отказа, в этой архитектуре он полностью лишен состояния, что означает, что его можно заменить пассивным резервом, щелкнув переключателем, что практически не приводит к простою предприятия.
В специальной зоне DMZ нашей сети находятся два набора приложений Java EE, работающих на резервных серверах. Эти приложения обрабатывают запросы от киосков на местах, а также для общего публичного использования через Интернет. Приложения не обращают внимания на безопасность перед ними и занимаются только выполнением бизнес-логики. Два дополнительных сервиса дополняют инфраструктуру. Первый отвечает за обработку всех кредитных карт в защищенной сети, которая отделена от локальной сети сервера приложений, корпоративной локальной сети и любой другой локальной сети в наших стенах. Последний критический компонент — сервер сертификатов EJBCA, который обеспечивает полную архитектуру защищенного сервиса.
На данный момент, у нас есть киоски, развернутые в географически большой области от Нью-Мексико до Мэна. Устройства киоска могут быть отправлены из нашего офиса клиенту и являются подключаемыми с точки зрения клиента. Что наиболее важно, удовлетворенность клиентов для киоска очень высока, поскольку он уменьшает их рабочую нагрузку и позволяет объекту сосредоточиться на главной задаче защиты населения и заключенных, содержащихся в его стенах.
Разработка была завершена, и первый киоск был развернут в течение 9 месяцев, главным образом благодаря единственному ресурсу разработки, доступному в любой момент времени. Это включает в себя время для разработки программного обеспечения киоска, серверной логики приложения и дизайна развертывания.
Вывод
Хотя наш подход не может быть классифицирован как классический дизайн SOA, из-за того, что мы не покупали чей-либо продукт для его реализации, он воплощает в себе многие из желательных атрибутов, которых стремится достичь SOA. Бизнес-логика централизована в группу основных серверов, которые обеспечивают отдельные, четко определенные действия для клиентов. Службы слабо связаны между собой, что позволяет мирно сосуществовать нескольким версиям программного обеспечения для киосков и веб-сайтов. Эта архитектура также обеспечивает стандартизированный способ управления доступом к ресурсам через известный продукт Apache. Одна и та же архитектура была наложена на два разных бизнес-процесса, что дало им обоим общую точку взаимодействия, даже если их цели различны. Устройство киоска, как потребитель услуг, объединяет их в один общий интерфейс,в то время как наш телефон IVR предоставляет еще один интерфейс с теми же данными.
Поскольку мы продолжаем добавлять дополнительных клиентов в нашу инфраструктуру, нам еще предстоит увидеть момент, когда мы перенасыщем любой компонент нашей системы. Если бы мне нужно было сделать предположение, я бы подумал, что сервер Apache будет первой точкой, где мы начнем испытывать нагрузку. В этот момент мы, вероятно, добавим второй веб-сервер, который является активным клоном первого, и разместим аппаратные балансировщики нагрузки перед ними. Но до этого момента DSI / ITI будет продолжать получать максимальную отдачу от нашего дизайна.