Изменить

Поделиться через


Защита решений MLOps с помощью сетевой безопасности Azure

Azure DevOps
Azure DNS
Машинное обучение Azure
Приватный канал Azure
Виртуальная сеть Azure

Машинное обучение DevOps (MLOps), сначала выделен в Скрытый технический долг в системах Машинное обучение в 2015 году быстро растет. Ожидается, что рынок MLOps достигнет $ 4 млрд к 2025 году. В то же время работа над обеспечением безопасности решений MLOps становится все более важной.

В этой статье описывается, как защитить решения MLOps с помощью возможностей безопасности сети Azure, таких как Azure виртуальная сеть, пиринг сети, Приватный канал Azure и Azure DNS. Он также содержит сведения об использовании:

  • Azure Pipelines для доступа к ресурсам в виртуальной сети
  • Необходимые конфигурации Реестр контейнеров Azure и Машинное обучение Azure вычислительных экземпляров и кластеров в виртуальной сети.

Наконец, в этой статье описываются затраты на использование служб безопасности сети.

Архитектура

Схема этапов процесса MLOps от подготовки данных к мониторингу модели.

Скачайте файл Visio для этой архитектуры.

Поток данных

На схеме архитектуры показан пример решения MLOps.

  • Виртуальная сеть с именем AML VNET помогает защитить рабочую область Машинное обучение Azure и связанные с ней ресурсы.

  • Узел перехода, Бастион Azure и локальные агенты принадлежат другой виртуальной сети с именем BASTION VNET. Это соглашение имитирует наличие другого решения, требующего доступа к ресурсам в Машинное обучение Azure виртуальной сети.

  • С поддержкой пиринга виртуальной сети и частных зон DNS Azure Pipelines может выполняться на агентах самообслуживания и активировать конвейеры Машинное обучение Azure, опубликованные в рабочей области Машинное обучение Azure для обучения, оценки и регистрации моделей машинного обучения.

  • Наконец, модель развертывается в сетевых конечных точках или пакетных конечных точках, поддерживаемых Машинное обучение Azure вычислительными или Служба Azure Kubernetes кластерами.

Компоненты

Пример решения MLOps состоит из следующих компонентов:

В этом примере также используются следующие службы для защиты решения MLOps:

Подробности сценария

MLOps — это набор методик на пересечении Машинное обучение, DevOps и проектирования данных, направленных на развертывание и обслуживание моделей машинного обучения в рабочей среде надежно и эффективно.

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

Схема этапов процесса MLOps от подготовки данных к мониторингу модели.

При реализации решения MLOps может потребоваться защитить эти ресурсы:

  • Конвейеры DevOps
  • Данные обучения машинного обучения
  • Конвейеры машинного обучения
  • Модели машинного обучения

Чтобы защитить ресурсы, рассмотрите следующие методы:

  • Проверка подлинности и авторизация

  • Безопасность сети

    • Используйте виртуальная сеть для частичной или полной изоляции среды от общедоступного Интернета, чтобы уменьшить область атаки и возможность кражи данных.
      • В рабочей области Машинное обучение Azure, если вы по-прежнему используете Машинное обучение Azure CLI версии 1 и Машинное обучение Azure пакет SDK Python версии 1 (например, API версии 1), добавьте частную конечную точку в рабочую область, чтобы обеспечить сетевую изоляцию для всех операций создания, чтения, обновления и удаления (CRUD) в рабочей области. рабочие области или вычислительные ресурсы.
      • Чтобы воспользоваться новыми функциями рабочей области Машинное обучение Azure, используйте интерфейс командной строки Машинное обучение Azure версии 2 и Машинное обучение Azure пакет SDK для Python версии 2 (например, API версии 2), в котором включение частной конечной точки в рабочей области не обеспечивает тот же уровень сетевой изоляции. Однако виртуальная сеть по-прежнему поможет защитить обучающие данные и модели машинного обучения. Мы рекомендуем оценить API версии 2 перед его внедрением в корпоративных решениях. Дополнительные сведения см. в статье "Что такое новая платформа API в Azure Resource Manager".
  • Шифрование данных

  • Политика и мониторинг

    • Используйте Политика Azure и Microsoft Defender для облака для применения политик.
    • Используйте Azure Monitor для сбора и агрегирования данных (таких как метрики и журналы) из различных источников в общую платформу данных для анализа, визуализации и оповещений.

Рабочая область Машинное обучение Azure — это ресурс верхнего уровня для Машинное обучение Azure и основной компонент решения MLOps. Рабочая область предоставляет централизованное место для работы со всеми артефактами, создаваемыми при использовании Машинное обучение Azure.

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

  • Azure Application Insights
  • Реестр контейнеров Azure
  • Azure Key Vault
  • Учетная запись хранения Azure

Потенциальные варианты использования

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

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

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

Решения MLOps для этих сценариев и другие могут использовать рабочие области Машинное обучение Azure, Хранилище BLOB-объектов Azure, Служба Azure Kubernetes, Реестр контейнеров и другие службы Azure.

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

Рекомендации

Эти рекомендации реализуют основные принципы azure Well-Architected Framework, которые являются набором руководящих принципов, которые повышают качество рабочей нагрузки при применении. Дополнительные сведения см. в статье Microsoft Azure Well-Architected Framework.

Безопасность

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

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

Оптимизация затрат

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

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

Служба Azure Цены
Виртуальная сеть За них не взимается плата.
Приватный канал Оплачивайте только часы ресурсов частной конечной точки и данные, обрабатываемые через частную конечную точку.
Azure DNS, частная зона Выставление счетов основано на количестве зон DNS, размещенных в Azure, и количестве полученных ЗАПРОСОВ DNS.
Пиринг между виртуальными сетями Плата за входящий и исходящий трафик взимается для обоих концов пиринговых сетей.
VPN-шлюз Плата зависит от времени подготовки и доступности шлюза.
ExpressRoute Плата взимается за шлюзы ExpressRoute и ExpressRoute.
Бастион Azure Выставление счетов включает в себя сочетание почасовых цен, основанных на номерах SKU, единицах масштабирования и тарифах передачи данных.

Эффективность работы

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

Чтобы упростить непрерывную интеграцию и непрерывную доставку (CI/CD), рекомендуется использовать средства и службы для инфраструктуры в качестве кода (IaC), такие как шаблоны Terraform или Azure Resource Manager, Azure DevOps и Azure Pipelines.

Развертывание этого сценария

В следующих разделах описывается развертывание, доступ и помощь в защите ресурсов в этом примере.

Виртуальная сеть

Первым шагом в защите среды MLOps является защита рабочей области Машинное обучение Azure и связанных с ней ресурсов. Эффективным способом защиты является использование виртуальная сеть. Виртуальная сеть — это стандартный строительный блок для вашей частной сети в Azure. виртуальная сеть позволяет многим типам ресурсов Azure более безопасно взаимодействовать друг с другом, Интернетом и локальными сетями.

Размещение рабочей области Машинное обучение Azure и связанных с ней ресурсов в виртуальной сети помогает гарантировать, что компоненты могут взаимодействовать друг с другом, не предоставляя их общедоступному Интернету. Это снижает уровень атак и помогает предотвратить кражу данных.

В следующем фрагменте кода Terraform показано, как создать вычислительный кластер для Машинное обучение Azure, подключить его к рабочей области и поместить его в подсеть виртуальной сети.

resource "azurerm_machine_learning_compute_cluster" "compute_cluster" {
  name                          = "my_compute_cluster"
  location                      = "eastasia"
  vm_priority                   = "LowPriority"
  vm_size                       = "Standard_NC6s_v3"
  machine_learning_workspace_id = azurerm_machine_learning_workspace.my_workspace.id
  subnet_resource_id            = azurerm_subnet.compute_subnet.id
  ssh_public_access_enabled     = false
  scale_settings {
    min_node_count                       = 0
    max_node_count                       = 3
    scale_down_nodes_after_idle_duration = "PT30S"
  }
  identity {
    type = "SystemAssigned"
  }
}

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

В этом примере существует четыре частные конечные точки, привязанные к параметрам Azure PaaS и управляемые подсетью в Машинное обучение Azure виртуальной сети, как показано на схеме архитектуры. Поэтому эти службы доступны только для ресурсов в одной виртуальной сети, Машинное обучение Azure виртуальной сети. Эти службы:

  • Рабочая область службы "Машинное обучение Azure"
  • Хранилище BLOB-объектов Azure
  • Реестр контейнеров Azure
  • Azure Key Vault

В следующем фрагменте кода Terraform показано, как использовать частную конечную точку для связывания с рабочей областью Машинное обучение Azure, которая более защищена виртуальной сетью в результате. В фрагменте кода также показано использование частной зоны DNS, описанной в зонах Частная зона DNS Azure.

resource "azurerm_machine_learning_workspace" "aml_ws" {
  name                    = "my_aml_workspace"
  friendly_name           = "my_aml_workspace"
  location                = "eastasia"
  resource_group_name     = "my_resource_group"
  application_insights_id = azurerm_application_insights.my_ai.id
  key_vault_id            = azurerm_key_vault.my_kv.id
  storage_account_id      = azurerm_storage_account.my_sa.id
  container_registry_id   = azurerm_container_registry.my_acr_aml.id

  identity {
    type = "SystemAssigned"
  }
}

# Configure private DNS zones

resource "azurerm_private_dns_zone" "ws_zone_api" {
  name                = "privatelink.api.azureml.ms"
  resource_group_name = var.RESOURCE_GROUP
}

resource "azurerm_private_dns_zone" "ws_zone_notebooks" {
  name                = "privatelink.notebooks.azure.net"
  resource_group_name = var.RESOURCE_GROUP
}

# Link DNS zones to the virtual network

resource "azurerm_private_dns_zone_virtual_network_link" "ws_zone_api_link" {
  name                  = "ws_zone_link_api"
  resource_group_name   = "my_resource_group"
  private_dns_zone_name = azurerm_private_dns_zone.ws_zone_api.name
  virtual_network_id    = azurerm_virtual_network.aml_vnet.id
}

resource "azurerm_private_dns_zone_virtual_network_link" "ws_zone_notebooks_link" {
  name                  = "ws_zone_link_notebooks"
  resource_group_name   = "my_resource_group"
  private_dns_zone_name = azurerm_private_dns_zone.ws_zone_notebooks.name
  virtual_network_id    = azurerm_virtual_network.aml_vnet.id
}

# Configure private endpoints

resource "azurerm_private_endpoint" "ws_pe" {
  name                = "my_aml_ws_pe"
  location            = "eastasia"
  resource_group_name = "my_resource_group"
  subnet_id           = azurerm_subnet.my_subnet.id

  private_service_connection {
    name                           = "my_aml_ws_psc"
    private_connection_resource_id = azurerm_machine_learning_workspace.aml_ws.id
    subresource_names              = ["amlworkspace"]
    is_manual_connection           = false
  }

  private_dns_zone_group {
    name                 = "private-dns-zone-group-ws"
    private_dns_zone_ids = [azurerm_private_dns_zone.ws_zone_api.id, azurerm_private_dns_zone.ws_zone_notebooks.id]
  }

  # Add the private link after configuring the workspace
  depends_on = [azurerm_machine_learning_compute_instance.compute_instance, azurerm_machine_learning_compute_cluster.compute_cluster]
}

Предыдущий код для azurerm_machine_learning_workspace использования платформы API версии 2 по умолчанию. Если вы по-прежнему хотите использовать API версии 1 или у вас есть политика компании, которая запрещает отправку сообщений через общедоступные сети, можно включить v1_legacy_mode_enabled параметр, как показано в следующем фрагменте кода. Это отключает API версии 2 для вашей рабочей области.

resource "azurerm_machine_learning_workspace" "aml_ws" {
  ...
  public_network_access_enabled = false
  v1_legacy_mode_enabled  = true
}

Частные зоны DNS Azure.

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

В этом примере решения используются частные конечные точки для рабочей области Машинное обучение Azure и связанные с ним ресурсы, такие как служба хранилища Azure, Azure Key Vault или Реестр контейнеров. Поэтому необходимо настроить параметры DNS для разрешения IP-адресов частных конечных точек из полного доменного имени (FQDN) строка подключения.

Вы можете связать частную зону DNS с виртуальной сетью для разрешения определенных доменов.

Фрагмент кода Terraform в Приватный канал и частной конечной точке Azure создает две частные зоны DNS с помощью имен зон, рекомендуемых в конфигурации зоны DNS служб Azure:

  • privatelink.api.azureml.ms
  • privatelink.notebooks.azure.net

Пиринг между виртуальными сетями

Пиринг между виртуальными сетями позволяет получить доступ к виртуальным машинам виртуальной машины или локальной виртуальной машине агента в виртуальной сети Бастиона Azure к ресурсам в Машинное обучение Azure виртуальной сети. В целях подключения две виртуальные сети работают в качестве одного. Трафик между виртуальными машинами и ресурсами Машинное обучение Azure в одноранговых виртуальных сетях использует магистральную инфраструктуру Azure. Трафик между виртуальными сетями направляется через частную сеть Azure.

Следующий фрагмент кода Terraform настраивает пиринг между виртуальной сетью Машинное обучение Azure виртуальной сетью и виртуальной сетью Бастиона Azure.

# Virtual network peering for AML VNET and BASTION VNET
resource "azurerm_virtual_network_peering" "vp_amlvnet_basvnet" {
  name                      = "vp_amlvnet_basvnet"
  resource_group_name       = "my_resource_group"
  virtual_network_name      = azurerm_virtual_network.amlvnet.name
  remote_virtual_network_id = azurerm_virtual_network.basvnet.id
  allow_virtual_network_access = true
  allow_forwarded_traffic      = true
}

resource "azurerm_virtual_network_peering" "vp_basvnet_amlvnet" {
  name                      = "vp_basvnet_amlvnet"
  resource_group_name       = "my_resource_group"
  virtual_network_name      = azurerm_virtual_network.basvnet.name
  remote_virtual_network_id = azurerm_virtual_network.amlvnet.id
  allow_virtual_network_access = true
  allow_forwarded_traffic      = true
}

Доступ к ресурсам в виртуальной сети

Чтобы получить доступ к рабочей области Машинное обучение Azure в виртуальной сети, например Машинное обучение Azure виртуальной сети в этом сценарии, используйте один из следующих методов:

  • VPN-шлюз Azure
  • Azure ExpressRoute
  • Бастион Azure и виртуальная машина узла перехода

Дополнительные сведения см. в разделе "Подключение к рабочей области".

Запуск Azure Pipelines, обращаюющихся к ресурсам в виртуальной сети

Служба Azure Pipelines автоматически создает и тестирует проекты кода и предоставляет их другим пользователям. Azure Pipelines объединяет CI/CD для тестирования и сборки кода и отправки его в любой целевой объект.

Размещенные в Azure агенты и локальные агенты

Решение MLOps в этом примере состоит из двух конвейеров, которые могут активировать Машинное обучение Azure конвейеры и доступ к связанным ресурсам. Так как рабочая область Машинное обучение Azure и связанный с ним ресурс находятся в виртуальной сети, этот сценарий должен предоставить агенту Azure Pipelines способ доступа к ним. Агент вычисляет инфраструктуру с установленным программным обеспечением агента, которое выполняет задания Azure Pipelines по одному за раз. Существует несколько способов реализации доступа:

  • Используйте автономные агенты в той же виртуальной сети или в пиринговой виртуальной сети, как показано на схеме архитектуры.

  • Используйте агенты, размещенные в Azure, и добавьте их диапазоны IP-адресов в список разрешений в параметрах брандмауэра целевых служб Azure.

  • Используйте размещенные в Azure агенты (как VPN-клиенты) и VPN-шлюз.

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

Размещенный в Azure агент Локальный агент
Стоимость Начните бесплатно для одного параллельного задания с 1800 минут в месяц и плата за каждое параллельное задание CI/CD, размещенное в Azure. Начните бесплатно для одного параллельного задания с неограниченными минутами в месяц и плата за каждое дополнительное локальное задание CI/CD с неограниченными минутами. Этот вариант предлагает менее дорогие параллельные задания.
Обслуживание Заботитесь о вас корпорацией Майкрософт. Поддерживается с дополнительным контролем над установкой программного обеспечения, которое вам нравится.
Время сборки Больше времени, так как он полностью обновляется каждый раз при запуске сборки, и вы всегда создаете с нуля. Экономит время, так как сохраняет все файлы и кэши.

Примечание.

Сведения о текущих ценах см. в разделе "Цены на Azure DevOps".

На основе сравнений в таблице и соображений безопасности и сложности в этом примере используется автономный агент для Azure Pipelines для активации конвейеров Машинное обучение Azure в виртуальной сети.

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

  • Установите агент в Azure Виртуальные машины.

  • Установите агенты в масштабируемом наборе виртуальных машин Azure, который можно автоматически масштабировать в соответствии с требованиями.

  • Установите агент в контейнере Docker. Этот параметр не подходит, так как в этом сценарии может потребоваться запуск контейнера Docker в агенте для обучения модели машинного обучения.

Следующий пример кода подготавливает два локальных агента путем создания виртуальных машин и расширений Azure:

resource "azurerm_linux_virtual_machine" "agent" {
  ...
}

resource "azurerm_virtual_machine_extension" "update-vm" {
  count                = 2
  name                 = "update-vm${format("%02d", count.index)}"
  publisher            = "Microsoft.Azure.Extensions"
  type                 = "CustomScript"
  type_handler_version = "2.1"
  virtual_machine_id   = element(azurerm_linux_virtual_machine.agent.*.id, count.index)

  settings = <<SETTINGS
    {
        "script": "${base64encode(templatefile("../scripts/terraform/agent_init.sh", {
          AGENT_USERNAME      = "${var.AGENT_USERNAME}",
          ADO_PAT             = "${var.ADO_PAT}",
          ADO_ORG_SERVICE_URL = "${var.ADO_ORG_SERVICE_URL}",
          AGENT_POOL          = "${var.AGENT_POOL}"
        }))}"
    }
SETTINGS
}

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

#!/bin/sh
# Install other required libraries 
...

# Creates directory and downloads Azure DevOps agent installation files
# Find more agent versions at https://github.com/microsoft/azure-pipelines-agent/releases
AGENT_VERSION="3.240.1"
sudo mkdir /myagent 
cd /myagent
sudo wget https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz
sudo tar zxvf ./vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz
sudo chmod -R 777 /myagent

# Unattended installation
sudo runuser -l ${AGENT_USERNAME} -c '/myagent/config.sh --unattended  --url ${ADO_ORG_SERVICE_URL} --auth pat --token ${ADO_PAT} --pool ${AGENT_POOL}'

cd /myagent
#Configure as a service
sudo ./svc.sh install ${AGENT_USERNAME}
#Start service
sudo ./svc.sh start

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

Существует несколько предварительных требований для защиты рабочей области Машинное обучение Azure в виртуальной сети. Дополнительные сведения см. в разделе Необходимые условия. Реестр контейнеров является обязательной службой при использовании рабочей области Машинное обучение Azure для обучения и развертывания моделей.

В этом примере для обеспечения доступа к реестру контейнеров в виртуальной сети для локального агента мы используем пиринг виртуальной сети и добавим ссылку виртуальной сети для связывания частной зоны DNS с privatelink.azurecr.ioвиртуальной сетью Бастиона Azure. В следующем фрагменте кода Terraform показана реализация.

# Azure Machine Learning Container Registry is for private access 
# by the Azure Machine Learning workspace
resource "azurerm_container_registry" "acr" {
  name                     = "my_acr"
  resource_group_name      = "my_resource_group"
  location                 = "eastasia"
  sku                      = "Premium"
  admin_enabled            = true
  public_network_access_enabled = false
}

resource "azurerm_private_dns_zone" "acr_zone" {
  name                     = "privatelink.azurecr.io"
  resource_group_name      = "my_resource_group"
}

resource "azurerm_private_dns_zone_virtual_network_link" "acr_zone_link" {
  name                  = "link_acr"
  resource_group_name   = "my_resource_group"
  private_dns_zone_name = azurerm_private_dns_zone.acr_zone.name
  virtual_network_id    = azurerm_virtual_network.amlvnet.id
}

resource "azurerm_private_endpoint" "acr_ep" {
  name                = "acr_pe"
  resource_group_name = "my_resource_group"
  location            = "eastasia"
  subnet_id           = azurerm_subnet.aml_subnet.id

  private_service_connection {
    name                           = "acr_psc"
    private_connection_resource_id = azurerm_container_registry.acr.id
    subresource_names              = ["registry"]
    is_manual_connection           = false
  }

  private_dns_zone_group {
    name                 = "private-dns-zone-group-app-acr"
    private_dns_zone_ids = [azurerm_private_dns_zone.acr_zone.id]
  }
}

В этом примере также гарантируется, что реестр контейнеров имеет роль участника для управляемого удостоверения, назначаемого системой Машинное обучение Azure рабочей области.

Использование вычислительного кластера или экземпляра в виртуальной сети

Для Машинное обучение Azure вычислительного кластера или экземпляра в виртуальной сети требуется группа безопасности сети (NSG) с определенными правилами для ее подсети. Список этих правил см. в разделе "Ограничения".

Кроме того, обратите внимание, что для вычислительного кластера или экземпляра теперь можно удалить общедоступный IP-адрес, который помогает обеспечить лучшую защиту вычислительных ресурсов в решении MLOps. Дополнительные сведения см. в разделе "Нет общедоступного IP-адреса для вычислительных экземпляров".

Соавторы

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

Основные авторы:

  • Гэри Ван | Главный инженер программного обеспечения

Другие участники:

Чтобы просмотреть недоступные профили LinkedIn, войдите в LinkedIn.

Следующие шаги