Рубрики
Без рубрики

Настройка авторизации для функций облачных HTTP в GCP

Облачные функции в GCP (Google Cloud Platform) – это легкий, несущественный, и безвестный вариант … Помечено с облаком Google, Python, облачных функций, авторизации.

Облачные функции в GCP (платформа Google Cloud) – это легкая, нестандартная, безвесочная, и неверная опция для выполнения кода, который запускается событием. Они эквивалентны лямбдасу в AWS (Amazon Web Services) или функции Azure в Microsoft Azure. События, которые вызывают облачную функцию, включают пабы/подпункты, события хранения облаков, такие как создание или удаление объекта хранения и HTTP-запросы.

Как и в случае с любым облачным обслуживанием, вы хотите убедиться, что люди и ресурсы, взаимодействующие с вашей облачной функцией, уполномочены для этого. С помощью Pub/Sub и Cloud Storagers несут ответственность за ограничение, у кого есть возможность вызывать вашу облачную функцию, отложено в IAM (управление идентификацией и доступом), связанным с этими ресурсами, однако с HTTP Triggers вам придется управлять разрешениями, настройки и присвоение одной или нескольких учетной записи Google и/или сервисной учетной записи с авторизацией для вызова вашей облачной функции.

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

gcloud functions deploy my-new-function `
--entry-point handle_request`
--runtime python38 `
--trigger-http

Allow unauthenticated invocations of new function
[my-new-function]? (y/N)?

Позволяя неактуальным вызовам, вы делаете конечную точку вашей облачной функции доступны в открытый Интернет. Если разрешение неактуальных вызовов является желаемое поведение, вы можете обойти этот вопрос при развертывании через SDK с помощью дополнительного флага - Allow - неаутентифицировано с Функции GCloud Развертывают команда. Неопределенные функции облачных функций должны быть исключением; Для большинства случаев использования вы захотите некоторую форму аутентификации и авторизации.

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

  1. Человек или услуга, уполномоченные, чтобы вызвать облачную функцию, должны быть назначены CloudFunctions.invoker Роль или какая-то другая роль с CloudFunctions.invoke разрешение.
  2. Человек или сервис, уполномоченный вызвать облачную функцию, должен отправить токен вместе с HTTP-запросом, чтобы доказать, что они авторизованы, чтобы вызвать функцию облака.

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

Вызов функции к функциям

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

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

import os
import requests

from dotenv import load_dotenv


load_dotenv()
CALLED_CLOUD_FUNCTION_URL = os.getenv('CALLED_CLOUD_FUNCTION_URL')


def send_request_to_called_cloud_function(request):
    request_body = request.get_json(silent=True)

    if not is_valid_request(request_body):
        return 'bad request, missing required field "foo"', 400

    called_func_request = prepare_called_func_request(request_body)

    token = request_token()
    headers = create_request_headers(token)

    called_func_response = requests.post(CALLED_CLOUD_FUNCTION_URL, json=called_func_request, headers=headers)

    return called_func_response.text, called_func_response.status_code

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

def request_token():
    metadata_server_url = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience='
    token_request_url = metadata_server_url + CALLED_CLOUD_FUNCTION_URL
    headers = {'Metadata-Flavor': 'Google'}

    token_response = requests.get(token_request_url, headers=headers)
    token = token_response.text

    return token


def create_request_headers(token):
    headers = {
        'content-type': 'application/json',
        'authorization': f'bearer {token}'
    }

    return headers

Будь то виртуальная машина, функция облака или приложение приложений, все вычислительные ресурсы в GCP имеют сервер, где хранятся соответствующие метаданные по поводу ресурса. Запрос на URL-адрес сервера метаданных в Request_token Функция проверяет метаданные функции Caller Cloud и проверяя, что учетная запись службы, прикрепленная к нему, уполномочена вызывать предполагаемую аудиторию запроса, называемой функцией облака. Если учетная запись услуг для абонента правильно установлена, ваша функция получит действительный токен для отправки во вторую функцию облака.

Как вы создаете учетную запись службы, которая авторизована, чтобы вызвать облачную функцию? Вы можете либо Создать новую учетную запись услуг Использование консоли или gcloud SDK и дать ему CloudFunctions.invoker Роль или вы можете управлять своими ресурсами IAM, используя IAC (инфраструктуру в качестве кода) решением, такого как террафору.

resource "google_service_account" "caller_cloud_function_sa" {
    project      = "my-cloud-function-project"
    account_id   = "caller-cloud-function-sa"
    display_name = "Caller Cloud Function Service Account"
}

resource "google_cloud_functions_function" "caller_cloud_function" {
    project               = "my-cloud-function-project"
    name                  = "caller-cloud-function"
    entry_point           = "send_request_to_called_cloud_function"
    runtime               = "python38"
    service_account_email = google_service_account.caller_cloud_function_sa.email
    trigger_http          = true
}

resource "google_cloudfunctions_function_iam_member" "cloud_function_invoker" {
    project        = google_cloud_functions_function.caller_cloud_function.project
    region         = google_cloud_functions_function.caller_cloud_function.region
    cloud_function = google_cloud_functions_function.caller_cloud_function.name

    role   = "roles/cloudfunctions.invoker"
    member = "serviceAccount:${google_service_account.caller_cloud_function_sa.email}"
}

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

from flask import jsonify


def respond_to_caller_cloud_function_request(request):
    request_body = request.get_json(silent=True)

    if not is_valid_request(request_body):
        return 'bad request, missing required field "bar"', 400

    new_entity = save_request_body(request_body)

    return jsonify(new_entity), 201

и развернуть оба облачных функций из консоли, gcloud SDK или через некоторые другие средства, такие как террафор.

# using powershell and the gcloud sdk to deploy both cloud functions
gcloud functions deploy caller-cloud-function `
--entry-point send_request_to_called_cloud_function `
--runtime python38 `
--service-account caller-cloud-function-sa@my-cloud-function-project.iam.gserviceaccount.com `
--trigger-http `
--allow-unauthenticated

gcloud functions deploy called-cloud-function `
--entry-point respond_to_caller_cloud_function_request `
--runtime python38 `
--trigger-http

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

Тестирование вашей защищенной функции облака

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

Чтобы получить токен, сначала убедитесь, что вы вошли в свою учетную запись Google, используя gcloud SDK, и что у вас есть разрешение, чтобы вызвать облачную функцию. Это требует CloudFunctions.invoker роль или любая другая роль, которая включает CloudFunctions.invoke разрешение.

Если вам было присвоено одно из основных ролей редактор или владелец У вас будет CloudFunctions.invoke Разрешение уже, в противном случае вам нужно будет проверить список ролей/разрешений, назначенных на вашу учетную запись и, возможно, запросить роль с CloudFunctions.invoke Разрешение, добавленное кем-то на проект с возможностью предоставить IAM роли.

Чтобы войти в учетную запись Google, используя gcloud SDK, используйте команду

gcloud auth login

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

Как только вы вошли в систему, вы можете запросить токен с помощью команды

gcloud auth print-identity-token

Вы также можете сделать это программно с помощью Python

def request_identity_token():
    stream = os.popen('gcloud auth print-identity-token')
    token = stream.read()

    return token.strip()

А затем отправьте свой HTTP-запрос таким же образом. Функция вызывающего абонента делает.

import requests
from dotenv import load_dotenv


load_dotenv()
CALLED_CLOUD_FUNCTION_URL = os.getenv('CLOUD_FUNCTION_URL')


def send_test_request():
    content = {'foo': 'bar'}
    token = request_identity_token()
    headers = { 'content-type': 'application/json', 'authorization': f'bearer {token}'

    response = requests.post(CALLED_CLOUD_FUNCTION_URL, json=content, headers = headers)

При этом вы готовы начать развертывание функций HTTP Cloud, которые требуют аутентификации и тестировать эти функции с вашего локального компьютера. Если ваш корпус на использование требует авторизации для конечных пользователей или какого-либо другого сервиса или ресурса, которые могут варьироваться, но общий процесс присоединения CloudFunctions.invoker Роль учетной записи Google или учетной записи службы и учет учетной записи пользователя или ресурса создать токен перед вызовом функции, будет прежней.

Оригинал: “https://dev.to/jakewitcher/setting-up-authorization-for-http-cloud-functions-in-gcp-45bc”