Мне очень нравятся продукты Google, но иногда документация может быть до боли краткой или фрагментарной. Я прочитал этот невероятно красноречивый ответ человека, который был таким же невежественным, как и я, и который почувствовал себя обязанным написать пошаговое руководство для детей. К сожалению, его ответ был слишком специфичен для его проекта, а не для моего.
У меня есть ряд облачных функций из существующего проекта Firebase (развернутого до версии 2, но с тех пор реорганизованного для версии 2), которые я клонировал в новый проект, и сталкиваюсь с препятствиями, с которыми никогда раньше не сталкивался. Это связано с тем, что раньше все осуществлялось через Firebase, а теперь все делается в Google Cloud. А начиная с версии 2, GC был значительно улучшен протоколами безопасности и контролем разрешений, и, к сожалению, документация не поддерживается в актуальном состоянии.
Следующая функция выдает ошибку недостаточного разрешения:
const {initializeApp} = require("firebase-admin/app");
const {getAuth} = require("firebase-admin/auth");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
initializeApp();
exports.assignAdminPrivileges = onDocumentCreated("admins/{docId}", async (event) => {
try {
const doc = event.data.data();
const emailAddress = doc.private.emailAddress;
const userRecord = await getAuth().getUserByEmail(emailAddress);
return getAuth().setCustomUserClaims(userRecord.uid, {"admin": true});
} catch (error) {
throw new Error(error);
}
});
Насколько я понимаю, эта функция по умолчанию использует для аутентификации «учетную запись вычислительной службы по умолчанию» в Google Cloud, у которой недостаточно разрешений для выполнения этой задачи. И я считаю, что эта функция должна использовать вместо этого «служебную учетную запись Firebase Admin SDK», учетную запись службы, которая поставляется с этой учетной записью Google Cloud. Честно говоря, я даже не уверен, что это сработает, но для меня это имеет наибольший смысл. Есть несколько способов сделать это, и я считаю, что лучший подход для моего варианта использования — загрузить ключ сервисной учетной записи Firebase Admin SDK и каким-то образом использовать его при развертывании этой функции, несмотря на все предупреждения Гугл призывает меня не скачивать этот ключ. И я должен использовать этот ключ (упакованный в виде файла JSON) вместе с пользовательской инициализацией Admin SDK в исходном коде.
const {initializeApp} = require("firebase-admin/app");
initializeApp({
credential: // I think this is what I need, but what goes here?,
});
// and what do I do with the JSON file?
Credential
, чтобы функция использовала учетную запись службы Firebase Admin SDK для аутентификации?Пожалуйста, будьте как можно более конкретны, я буду очень признателен.
@RenaudTarnec Функция развертывается с использованием интерфейса командной строки Firebase. Развертывание не является проблемой. Проблема в вызове. Когда эта функция вызывается при изменении документа, она использует для аутентификации учетную запись службы GC по умолчанию, чего недостаточно для этой задачи. Мне нужно указать другую учетную запись службы, а именно учетную запись службы Firebase Admin SDK. Как мне это сделать — мой главный вопрос.
Если развертывание через Firebase CLI не является проблемой, это означает, что «Учетная запись службы вычислений по умолчанию» в IAM имеет роль «Создатель токена учетной записи службы». В противном случае во время развертывания вы получите сообщение об ошибке типа «Не удалось проверить, что проект имеет правильные привязки IAM для успешного развертывания». и несколько строк, показывающих команду для обновления учетной записи службы вычислений (например, [email protected]). Итак, можете ли вы подтвердить, что в Google Cloud Console учетная запись вычислительной службы (например, [email protected]) имеет эту роль?
(продолжение) Если эта роль назначена правильно, ваша облачная функция должна работать без проблем, всего лишь initializeApp();
@RenaudTarnec это совершенно новая учетная запись, организация и проект GC, поэтому все по-прежнему по умолчанию. По умолчанию «Учетная запись службы вычислений по умолчанию» имеет две роли: Cloud Run Invoker и Eventarc Event Receiver. Только firebase-adminsdk получила роль создателя токена сервисной учетной записи.
Если вы назначите роль «Создатель токена учетной записи службы» «Учетной записи службы вычислений по умолчанию», ваш CF должен работать.
Работа с Firebase совместно с Google Cloud (GC) уже не та, что была раньше. В отличие от предыдущего, GC теперь заблокирован и имеет встроенный контроль разрешений. Цель состоит в том, чтобы заставить проекты предоставлять конкретный доступ только тогда и там, где он необходим, по всем направлениям. Если вы хотите предоставить доступ к чему-то, вам часто придется сначала предоставить доступ себе, чтобы иметь возможность предоставить доступ к чему-то еще.
Когда вы развертываете облачные функции Firebase с помощью Firebase CLI, учетная запись, с которой выполнен вход в CLI, — это учетная запись, которой потребуются разрешения для выполнения развертывания. Скорее всего, это ваша учетная запись пользователя Firebase. В GC перейдите к IAM и предоставьте этой учетной записи пользователя необходимые роли. Нам никогда не говорят, какие роли необходимы, потому что Google хочет, чтобы мы специально выявляли ошибки, чтобы мы могли по сообщениям об ошибках точно расшифровать, какие разрешения необходимы. Так что сделайте это здесь.
После того, как вошедшая в систему учетная запись Firebase получит необходимые роли, вы должны инициализировать приложение в исходном коде с другим набором учетных данных. Здесь вы, вероятно, захотите инициализировать приложение с помощью учетной записи службы. Сервисные учетные записи — это учетные записи, как и любые другие, которые могут брать на себя роли, за исключением того, что у них нет владельцев, у них есть заемщики. Они предназначены для того, чтобы их мог одолжить кто угодно или что угодно, у кого есть разрешение на их заимствование. И идеальной сервисной учетной записью здесь, скорее всего, будет сервисная учетная запись Firebase Admin SDK, которая по умолчанию поставляется с каждым проектом Firebase и содержит широкий спектр ролей, важных для работы Firebase.
Официальная документация здесь немного сбивает с толку, поскольку она рекомендует как (а) ничего не передавать методу initializeApp()
в исходном коде (чтобы использовать учетную запись службы по умолчанию), так и (б) передавать учетные данные методу initializeApp()
, в идеале с использованием JSON-файл. Проблема в том, что использование учетных данных JSON представляет угрозу безопасности, о чем Google предупреждает вас, когда вы пытаетесь загрузить высокочувствительные ключи. Но если вы их не используете, учетная запись службы по умолчанию не подойдет, поскольку это не учетная запись службы Firebase Admin SDK, а учетная запись службы Compute Engine по умолчанию.
Существует третий вариант: изменить учетную запись службы по умолчанию для самой функции, что можно сделать либо в исходном коде, либо в GC. Чтобы сделать это в GC, сначала необходимо развернуть функцию, а затем перейти к Cloud Run, открыть функцию, отредактировать и развернуть новую версию, где вы можете изменить учетную запись службы по умолчанию на вкладке безопасности.
Чтобы сделать это в исходном коде, используйте объект GlobalOptions
:
setGlobalOptions({
serviceAccount: "[email protected]",
});
Если вместо этого вы предпочитаете использовать ключи, перейдите в IAM, затем перейдите к учетным записям служб, затем выберите учетную запись службы Firebase Admin SDK, затем перейдите к ключам и добавьте ключ (выберите JSON). Это позволит вам загрузить файл JSON на свой компьютер. Вы можете поместить этот файл в любое место на своем компьютере, но в этом примере я помещу его в папку «functions», где находится файл «index.js», и назову его «service-account-credentials.json». Имейте в виду, что размещение этого файла в общедоступных удаленных репозиториях может привести к отзыву этого ключа со стороны GC. Возможно, вы вообще не захотите проверять этот файл в системе контроля версий, в зависимости от вашей ситуации. В любом случае используйте этот файл для инициализации самого экземпляра приложения в исходном коде функции:
const {initializeApp, cert} = require("firebase-admin/app");
initializeApp({
credential: cert("./service-account-credentials.json"),
});
Обратите внимание, что для функций версии 1 вам потребуется использовать файл JSON. Настройка учетной записи службы в глобальных параметрах находится в API версии 2. Поэтому, если у вас есть сочетание функций v1 и v2, используйте обе — установите их глобально и предоставьте сертификат JSON.
Теперь вы сможете развертывать функции из интерфейса командной строки Firebase, и функции должны выполняться при вызове... в зависимости от того, что они делают.
Вы можете практически забыть о консоли Firebase для управления вашими облачными функциями, потому что теперь все выполняется в GC. Вы даже можете развернуть свои функции с помощью интерфейса командной строки gcloud, который более надежен, чем интерфейс командной строки Firebase, но здесь это не обязательно. Просто поймите, что ваши облачные функции развертываются в GC, а не в Firebase. Firebase — это уровень абстракции для облачных функций, который в основном полезен для просмотра того, что существует в GC.
По умолчанию функции, развернутые в GC, защищены средствами контроля разрешений, как и следовало ожидать, — в частности, все они требуют аутентификации для вызова. Таким образом, если вы развернули функцию, которую могут вызывать «случайные» клиенты, например пользователи приложения, например функцию, создающую учетную запись пользователя Firebase для пользователя, у которого ее еще нет, этот вызов завершится ошибкой с ошибкой ошибка разрешения. И это потому, что функция была вызвана неаутентифицированным объектом. Экземпляр приложения, который обслуживал функцию, был правильно инициализирован доверенной учетной записью службы (учетной записью службы Firebase Admin SDK), но объект, вызвавший функцию, был пользователем, не прошедшим проверку подлинности. В таком случае вам нужно перейти к Cloud Run (в GC), установить флажок рядом с этой функцией, перейти к разрешениям, добавить участника, ввести «allUsers» и выбрать Cloud Run/Cloud. Запустите роль Invoker. Если ваша функция по-прежнему учитывается для версии 1, это делается на вкладке «Облачные функции» и ролью является «Облачные функции/Вызов облачных функций». Теперь эту функцию могут вызывать неаутентифицированные пользователи.
Стоит отметить, что чтобы определить, какие роли следует добавить при возникновении ошибки, откройте GC, перейдите в раздел «Ведение журнала» и найдите ошибки в журнале. Разверните ошибки, чтобы прочитать их сообщения, и иногда они сообщат вам, какие именно разрешения отсутствуют, а в других случаях это потребует некоторой детективной работы.
Вы также, несомненно, столкнетесь с проблемами ограничений при попытке ослабить разрешения. Ограничения — это средства контроля разрешений, налагаемые на организации. Если вы столкнулись с ошибкой ограничения, например ошибкой ограничения общего доступа к домену, с которой вы, вероятно, столкнетесь в какой-то момент, перейдите к IAM, а затем перейдите к политикам организации. Здесь вы можете найти ограничение, которое мешает вам делать то, что вы пытаетесь сделать. Однако, чтобы отключить это ограничение, вам может потребоваться предоставить учетной записи, в которую вы вошли, роль, которая дает ей право изменять политики организации.
Как вы его развертываете? Обычно, если вы используете Firebase CLI, у вас не должно возникнуть проблем с вашим CF (первый фрагмент кода в вашем вопросе).