简体   繁体   English

在 GitHub 操作中验证 Firebase 连接

[英]Authenticating Firebase connection in GitHub Action

Background背景

I have a Python script that reads data from an Excel file and uploads each row as a separate document to a collection in Firestore.我有一个 Python 脚本,它从 Excel 文件中读取数据,并将每一行作为单独的文档上传到 Firestore 中的集合。 I want this script to run when I push a new version of the Excel file to GitHub.当我将 Excel 文件的新版本推送到 GitHub 时,我希望此脚本运行。

Setup设置

I placed the necessary credentials in GitHub repo secrets and setup the following workflow to run on push to my data/ directory:我将必要的凭据放入 GitHub repo secrets 并设置以下工作流程以在推送到我的data/目录时运行:

name: update_firestore

on:
  push:
    branches:
      - main
    paths:
      - data/**.xlsx

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: checkout repo content
        uses: actions/checkout@v2 # checkout the repository content to github runner.

      - name: setup python
        uses: actions/setup-python@v4
        with:
          python-version: '3.*' # install the latest python version

      - name: install python packages
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

      - name: execute python script
        env:
          TYPE: service_account
          PROJECT_ID: ${{ secrets.PROJECT_ID }}
          PRIVATE_KEY_ID: ${{ secrets.PRIVATE_KEY_ID }}
          PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
          CLIENT_EMAIL: ${{ secrets.CLIENT_EMAIL }}
          TOKEN_URI: ${{ secrets.TOKEN_URI }}
        run: python src/update_database.py -n ideas -delete -add

The Problem问题

I keep getting the following error:我不断收到以下错误:

Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.10.7/x64/lib/python3.10/site-packages/firebase_admin/credentials.py", line 96, in __init__
    self._g_credential = service_account.Credentials.from_service_account_info(
  File "/opt/hostedtoolcache/Python/3.10.7/x64/lib/python3.10/site-packages/google/oauth2/service_account.py", line 221, in from_service_account_info
    signer = _service_account_info.from_dict(
  File "/opt/hostedtoolcache/Python/3.10.7/x64/lib/python3.10/site-packages/google/auth/_service_account_info.py", line 58, in from_dict
    signer = crypt.RSASigner.from_service_account_info(data)
  File "/opt/hostedtoolcache/Python/3.10.7/x64/lib/python3.10/site-packages/google/auth/crypt/base.py", line 113, in from_service_account_info
    return cls.from_string(
  File "/opt/hostedtoolcache/Python/3.10.7/x64/lib/python3.10/site-packages/google/auth/crypt/_python_rsa.py", line 171, in from_string
    raise ValueError("No key could be detected.")
ValueError: No key could be detected.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/runner/work/IRIS/IRIS/src/update_database.py", line 9, in <module>
    import fire
  File "/home/runner/work/IRIS/IRIS/src/fire/__init__.py", line 35, in <module>
    cred = credentials.Certificate(create_keyfile_dict())
  File "/opt/hostedtoolcache/Python/3.10.7/x64/lib/python3.10/site-packages/firebase_admin/credentials.py", line 99, in __init__
    raise ValueError('Failed to initialize a certificate credential. '
ValueError: Failed to initialize a certificate credential. Caused by: "No key could be detected."
Error: Process completed with exit code 1.

My Attempted Solutions我尝试的解决方案

I have tried a variety of approaches including what I show above, just hardcoding each of the secrets, and copying the .json formatted credentials directly as a single secret.我尝试了多种方法,包括我上面展示的方法,只是对每个秘密进行硬编码,并将.json格式的凭据直接复制为一个秘密。 I know there are some issues dealing with multiline environment variables which the PRIVATE_KEY is.我知道有一些处理PRIVATE_KEY多行环境变量的问题。 I have tried:我试过了:

  1. Pasting the PRIVATE_KEY str directly from the download firebase provides which includes \n直接从下载 firebase 提供的PRIVATE_KEY str 粘贴,其中包括\n
  2. Removing escape characters and formatting the secret like:删除转义字符并格式化秘密,例如:
-----BEGIN PRIVATE KEY-----
BunC40fL3773R5AndNumb3r5
...
rAndomLettersANDNumb3R5==
-----END PRIVATE KEY-----

I feel like the solution should be pretty straight-forward but have been struggling and my knowledge with all this is a bit limited.我觉得解决方案应该非常简单,但一直在努力,我对这一切的了解有点有限。

Thank you in advance!先感谢您!

After hours of research, I found an easy way to store the Firestore service account JSON as a Github Secret.经过几个小时的研究,我找到了一种将 Firestore 服务帐户 JSON 存储为 Github Secret 的简单方法。

Step 1: Convert your service account JSON to base-64第 1 步:将您的服务帐户 JSON 转换为 base-64

Let's name the base-64 encoded JSON SERVICE_ACCOUNT_KEY .让我们将 base-64 编码命名为 JSON SERVICE_ACCOUNT_KEY There are two ways to get this value:有两种方法可以获取这个值:

Method 1: Using command line方法一:使用命令行

cat path-to-your-service-account.json | base64 | xargs

This will return a single line representing the encoded service account JSON. Copy this value.这将返回代表编码服务帐户 JSON 的单行。复制此值。

Method 2: Using python方法二:使用python

import json
import base64


service_key = {
    "type": "service_account",
    "project_id": "xxx",
    "private_key_id": "xxx",
    "private_key": "-----BEGIN PRIVATE KEY-----\nxxxxx\n-----END PRIVATE KEY-----\n",
    "client_email": "xxxx.com",
    "client_id": "xxxx",
    "auth_uri": "xxxx",
    "token_uri": "xxxx",
    "auth_provider_x509_cert_url": "xxxx",
    "client_x509_cert_url": "xxxx"
}

# convert json to a string
service_key = json.dumps(service_key)

# encode service key
SERVICE_ACCOUNT_KEY= base64.b64encode(service_key.encode('utf-8'))

print(SERVICE_ACCOUNT_KEY)
# FORMAT: b'a_long_string'

Copy only the value between the quotes .只复制引号之间的值。 (copy a_long_string instead of b'a_long_string' ) (复制a_long_string而不是b'a_long_string'

Step 2: Create your environment variable第 2 步:创建环境变量

I am using dotenv library to read environment variables.我正在使用dotenv 库来读取环境变量。 You will have to install it first using pip install python-dotenv .您必须先使用pip install python-dotenv安装它。 Also add this dependency in your requirements.txt for github actions.还要在您的requirements.txt中为 github 操作添加此依赖项。

  • Create a Github repository secret SERVICE_ACCOUNT_KEY which will store the base-64 value.创建一个 Github 存储库机密SERVICE_ACCOUNT_KEY ,它将存储 base-64 值。
  • In your Github YML file, add the environment variable:在你的 Github YML 文件中,添加环境变量:
      - name: execute py script 
        env:
          SERVICE_ACCOUNT_KEY: ${{ secrets.SERVICE_ACCOUNT_KEY }}
        run: python src/main.py 
  • To be able to test your program locally, you might also want to add SERVICE_ACCOUNT_KEY together with its value to your .env file (which should be in the root directory of your project).为了能够在本地测试您的程序,您可能还想将SERVICE_ACCOUNT_KEY及其值添加到您的.env文件(应该位于项目的根目录中)。 Remember to add .env to your .gitignore file to avoid exposing your key on Github.请记住将.env添加到您的.gitignore文件中,以避免在 Github 上暴露您的密钥。

Step 3: Decoding the service key第 3 步:解码服务密钥

You will now need to get the value of SERVICE_ACCOUNT_KEY in your Python code and convert this value back to a JSON. I am using the dotenv library to get the value of the SERVICE_ACCOUNT_KEY .您现在需要在 Python 代码中获取SERVICE_ACCOUNT_KEY的值,并将该值转换回 JSON。我正在使用dotenv库获取SERVICE_ACCOUNT_KEY的值。

import json
import base64
import os
from dotenv import load_dotenv, find_dotenv

# get the value of `SERVICE_ACCOUNT_KEY`environment variable
load_dotenv(find_dotenv())
encoded_key = os.getenv("SERVICE_ACCOUNT_KEY")

# decode
SERVICE_ACCOUNT_JSON = json.loads(base64.b64decode(encoded_key).decode('utf-8'))

# Use `SERVICE_ACCOUNT_JSON` later to initialse firestore db:
# cred = credentials.Certificate(SERVICE_ACCOUNT_JSON)
# firebase_admin.initialize_app(cred)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM