繁体   English   中英

用于将 Android 应用发布到 Google Play 控制台的 .NET 客户端工具的 Google 服务帐户的私钥问题

[英]Google Service Account's Private Key problems with .NET client tool used to publish Android app to Google Play Console

我正在创建一个名为 google-play-publisher 的开源工具,开发为 .NET 7 REST API 委托给Google API .NET Client

我的想法是在我的 GitLab CI/CD 管道中将它作为容器(即服务)运行,以便将 Android 应用程序(即:aab 文件)上传到 Google Play 开发人员,因为它公开了一个我可以使用curl调用的简单端点像这样:

curl -XPOST --data-binary @your_file.aab http://localhost:5000/api/apps/<your_package_name>/tracks/<track_name>

使持续交付变得方便。

我拥有让它工作所需的一切,包括具有适当角色和凭据的 Google 服务帐户,这是我的 Google Play 控制台已知的。

我将密钥下载为 JSON 格式,它的格式如下(假值):

{
  "type": "service_account",
  "project_id": "pc-api-...",
  "private_key_id": "5342dce..",
  "private_key": "-----BEGIN PRIVATE KEY-----\nbunchofcharacters\nandmorecharactes=\n-----END PRIVATE KEY-----\n",
  "client_email": "publisher@pc-api-foo-iam.gserviceaccount.com",
  "client_id": "123456",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/publisher@pc-api-foo-iam.gserviceaccount.com"
}

注意: -----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n是非常必要的。 如果删除,Google API .NET 客户端库将失败。

从那以后,我只需要 6 件事:

  1. type
  2. project_id
  3. private_key_id
  4. private_key
  5. client_email
  6. client_id

为了获得 Google Publisher v3 API 的授权,并将特定 package 的 AAB 上传到特定轨道。

应用程序只需要在启动时注入这 6 个设置,方法是在appsettings.json中配置它们,或者在启动容器时作为环境变量注入。 到目前为止相当标准。

我的appsettings.json看起来像这样(使用凭证 json 中的正确值)

  "ServiceAccount": {
    "PrivateKey": "***",
    "ClientEmail": "***",
    "ProjectId": "***",
    "Type": "***",
    "PrivateKeyId": "***",
    "ClientId": "***"
  },

当我使用正确的值配置此appsettings.json时,一切正常。

但我不想将appsettings.json用于机密。 我需要使用环境变量,以便我可以将该工具与 docker 一起使用,并在启动容器/服务时注入变量。

但是当将该工具作为 docker 容器或作为 GitLab CI/CD 管道内的服务运行时,我遇到了一些问题

问题 1 - Docker 运行不喜欢私钥格式

当我像这样将工具(版本 0.1.8)作为 docker 容器运行时

docker run \
  --name google-play-publisher \
  -p 5000:80 \
  -e ServiceAccount__PrivateKey="-----BEGIN PRIVATE KEY-----\nbunchofcharacters\nandmorecharactes=\n-----END PRIVATE KEY-----\n" \
  -e ServiceAccount__ClientEmail="publisher@pc-api-foo-iam.gserviceaccount.com" \
  -e ServiceAccount__ProjectId="pc-api-..."\
  -e ServiceAccount__Type="service_account" \
  -e ServiceAccount__PrivateKeyId="5342dce.." \
  -e ServiceAccount__ClientId="123456" \
  registry.gitlab.com/roundev/devops/google-play-publisher:0.1.8

然后我发布一个packageaab 文件

curl -XPOST --data-binary @my_file.aab http://localhost:5000/api/apps/com.foo.app/tracks/production

认证失败

System.ArgumentException: PKCS8 data must be contained within '-----BEGIN PRIVATE KEY-----' and '-----END PRIVATE KEY-----'. (Parameter 'pkcs8PrivateKey')

因为docker run似乎不喜欢传递带有\n字符等的特殊环境变量。

问题 2 - GitLab CI/CD 变量也不喜欢这种格式

它无法屏蔽它,这是一个问题,然后有些东西不起作用但我还看不到错误(没有显示错误,管道通过但 AAB 未上传,所以我需要想办法读取 GitLab CI/CD 服务日志,为此出自 scope) 在此处输入图像描述

解决方案尝试 1 - 将私钥值转换为 base64 并将其解码

我想在 base64 中编码私钥(不确定是否有其他选择)以获得以下优势:

  • GitLab CI/CD 变量可能被屏蔽
  • 将 base64 字符串作为环境变量传递时,Docker 运行不会表现异常

但这显示了一个不同的问题。 使用在线 base 64 编码器在代码中对其进行解码以生成 google 身份验证凭据是行不通的。 \n字符似乎把事情搞砸了。

我尝试了不同的变体,但在使用 Google Publisher API 时,我总是遇到一些invalid_token问题。

// Functions used for encoding and decoding
string EncodeBase64(string text)
{
    var textBytes = Encoding.UTF8.GetBytes(text);
    var result = Convert.ToBase64String(textBytes);
    return result;
}

string DecodeBase64(string base64Text)
{
    var base64EncodedBytes = Convert.FromBase64String(base64Text);
    var result = Encoding.UTF8.GetString(base64EncodedBytes);
    return result;
}

我还没有找到一个好的解决方案,可以让我:

  • 通过将私钥作为不会导致问题的环境变量传递,使我的工具与 docker 一起运行,这样它就可以像使用appsetting.json运行它一样工作
  • 将GitLab CI/CD中的环境变量以安全的方式配置为变量(这样就可以被屏蔽)。

必须有一个使用某种编码/解码私钥的好的解决方案。 但是怎么办?

我已经用十六进制方法解决了它。

基本上,解决方案是按原样获取private_key的 Json 值,并将其转换为十六进制,例如使用此在线工具https://codebeautify.org/string-hex-converter所以私钥看起来像这样"-----BEGIN PRIVATE KEY-----\nfoo...\nbar\n-----END PRIVATE KEY-----\n"现在看起来像这样2d2d2d2d2d424...b45592d2d2d2d2d5c6e

该字符串具有以下特征:

  • 在GitLab CI/CD中可以作为环境变量保护
  • 它可以作为 docker 环境变量传递
  • 它可以很容易地读取并转换为原始的private_key
private class JsonCredentials
{
    public string Type { get; init; } = string.Empty;
    public string PrivateKeyId { get; init; } = string.Empty;
    public string PrivateKeyHex { get; init; } = string.Empty;
    public string PrivateKey => ToJsonValue(PrivateKeyHex);
    public string ClientEmail { get; init; } = string.Empty;
    public string ProjectId { get; init; } = string.Empty;
    public string ClientId { get; init; } = string.Empty;

    private string ToJsonValue(string hexadecimalValue)
    {
        var hexadecimalValueBytes = Convert.FromHexString(hexadecimalValue);
        var result = Encoding.UTF8.GetString(hexadecimalValueBytes);
        var unescapedResult = Regex.Unescape(result);
        return unescapedResult;
    }
}

有关详细信息,请参阅我的开源存储库: https://gitlab.com/roundev/devops/google-play-publisher并尝试一下。

我相信您的问题是密钥中转义的新行 (/n),特别是使用 base 64 方法。

尝试通过将密钥粘贴到在线 base 64 编码器来生成 base 64 字符串,如下所示:

-----BEGIN PRIVATE KEY-----
Whatever
-----END PRIVATE KEY-----

而不是:

-----BEGIN PRIVATE KEY-----/nWhatever/n-----END PRIVATE KEY-----/n

与 Gitlab 相同。使用正确的换行符而不是/n粘贴您的密钥

在此处输入图像描述

关于docker run ,显然/n没有被解析为新行并按字面意思理解,因此您需要研究如何解决这个问题。 但基本上要么用代码中的新行替换它们,要么用 go 替换 base 64 string road。

暂无
暂无

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

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