Есть ли способ защитить функцию Azure, которая будет вызываться только из определенного приложения логики Azure?

Я понимаю, что функции Azure являются потенциально открытыми конечными точками в Интернете, если я правильно читаю документацию Microsoft и общаюсь с другом, у которого есть некоторый опыт работы с парадигмами веб-разработки, которые используются функциями Azure. Беглое чтение форумов по безопасности и вопросов переполнения стека по этой теме позволяет мне понять, по крайней мере, пару вариантов их защиты, а именно: 1) Azure Active Directory 2) подписи общего доступа (SAS) и 3) виртуальные сети Azure.

Контекст / Что делает моя функция Azure? Он управляет контейнером больших двоичных объектов, связанным с ETL данных поставщика, из источника SFTP в конечную точку SQL, в которой этот ETL использует промежуточный контейнер больших двоичных объектов для передачи файлов и долгосрочного холодного хранения исходных данных. Функция Azure перемещает большие двоичные объекты из одного контейнера в контейнер архива после их загрузки в конечную точку SQL. Зачем Azure Function управлять контейнерами больших двоичных объектов? 1) В SSIS отсутствует возможность выполнять операции с большими двоичными объектами (т. Е. Копировать и удалять). 2) В приложении логики отсутствует возможность выполнения объединения (файлов, загруженных в конечную точку SQL, и имен файлов в контейнере больших двоичных объектов).

Пример одной из функций ниже:

using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net;
using Microsoft.WindowsAzure.Storage.Blob;
using System.Collections.Generic;
using System.Text;

namespace AFA_ArchiveBlob
{
    public static class HttpTrigger_BlobInput
    {
        [FunctionName("HttpTrigger_BlobInput")]
        public static async Task<HttpResponseMessage> Run(
        //public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get",  Route = "{name}")] HttpRequest req,
            string name,
            ILogger log,
            [Blob("{name}/blobname",FileAccess.ReadWrite,Connection = "AzureWebJobsStorage")]  CloudBlobContainer myCloudBlobContainer
            )
        {
            //Execution Logged.
            log.LogInformation($"HttpTrigger_BlobInput - C# HTTP trigger function processed a request.");

            //Run the query against the blob to list the contents.
            BlobContinuationToken continuationToken = null;
            List<IListBlobItem> results = new List<IListBlobItem>();
            do
            {
                var response = await myCloudBlobContainer.ListBlobsSegmentedAsync(continuationToken);
                continuationToken = response.ContinuationToken;
                results.AddRange(response.Results);
            }
            while (continuationToken != null);

            //Query the names of the blobs. Todo: can this be a single line linq query select instead?
            List<string> listBlobNames = new List<string>();
            foreach (CloudBlockBlob b in results)
            {
                listBlobNames.Add(b.Name);
            }

            //Serialize the list of blob names to json for passing to function caller via return statement
            var jsonReturn = JsonConvert.SerializeObject(listBlobNames);

            log.LogInformation("Returning the following JSON");
            log.LogInformation(jsonReturn);

            return new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent(jsonReturn, Encoding.UTF8, "application/json")
            };
        }
    }
}

1 ответ

Решение

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

Я полагаю, что было бы лучше выбрать Azure Active Directory для обеспечения безопасности... как объясняется здесь Защита конечной точки HTTP на производстве

Как реализовать

Я вижу два возможных подхода:

1. Простой подход. Убедитесь, что вызывающее приложение специально предназначено для вашего приложения логики Azure.

Включите проверку подлинности Azure Active Directory для приложения-функции Azure. Вы можете просто использовать настройки Express (с созданием нового приложения Azure AD)

Включите идентификацию управляемого сервиса для вашего приложения логики.

Найдите appid для идентификатора управляемой службы, связанного с вашим приложением логики. Перейдите на портал Azure> Azure Active Directory > Корпоративные приложения> Все приложения> Соответствующий принципал службы (более подробно объяснено со снимками экрана в другой публикации SO здесь)

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

В коде вашей функции теперь вы можете проверить, что appid требование в маркере доступа должно точно соответствовать appid для приложения логики (т. е. приложение логики - это то, что вызывает вашу функцию).. в противном случае вы можете отклонить вызов с неавторизованным исключением.

2. Более декларативный подход. Определите разрешение приложения для приложения-функции Azure и проверьте наличие этого разрешения / роли в маркере авторизации от клиента, вызывающего вашу функцию.

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

Включите проверку подлинности Azure Active Directory для приложения-функции Azure. Вы можете просто использовать настройки Express (с созданием нового приложения Azure AD)

Теперь перейдите в Azure Active Directory> Регистрация приложений> Регистрация приложения для вашего функционального приложения> Манифест

Добавьте новую роль приложения.. используя json, например:

"appRoles": [
{
  "allowedMemberTypes": [
    "Application"
  ],
  "displayName": "Can invoke my function",
  "id": "fc803414-3c61-4ebc-a5e5-cd1675c14bbb",
  "isEnabled": true,
  "description": "Apps that have this role have the ability to invoke my Azure function",
  "value": "MyFunctionValidClient"
}]

Включите идентификацию управляемого сервиса для вашего приложения логики.

Найдите appid для идентификатора управляемой службы, связанного с вашим приложением логики... как уже объяснено в подходе 1 выше

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

New-AzureADServiceAppRoleAssignment -ObjectId <logicappmsi.ObjectId> -PrincipalId <logicappmsi.ObjectId> -Id "fc803414-3c61-4ebc-a5e5-cd1675c14bbb" -ResourceId <yourfunctionaadapp.ObjectId>

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

Теперь в токене авторизации, полученном вашей функцией, вы можете проверить, что role Сбор претензий должен содержать роль с именем "MyFunctionValidClient" в противном случае вы можете отклонить вызов с неавторизованным исключением.

В дополнение к вышеуказанным шагам, объясненным @Rohit, важен следующий шаг:

Перейдите в Host.json функции. По умолчанию authLevel: "функция" следует изменить на "authLevel": "анонимный".

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

Другие вопросы по тегам