glamstack/google-cloud-sdk

Google Cloud SDK for Laravel

2.5.25 2022-05-25 19:19 UTC

README

概览

Google Cloud SDK 是一个由 GitLab IT Engineering 创建的开源 Composer 包,用于 GitLab Access Manager Laravel 应用程序,以连接到 Google Cloud API 端点

免责声明:这不是由 Google 或 GitLab 产品和开发团队维护的官方包。这是一个我们作为公司价值观的一部分开源的 GitLab IT 部门内部工具。

请自行承担风险,并在遇到任何错误时创建问题。

我们不会维护社区功能请求路线图,但我们邀请您贡献,并且我们将乐意审查您的合并请求。

依赖项

注意:此包需要 glamstack/google-auth-sdk 包才能运行。这已在 composer.json 文件中配置为必需包,并在安装此包时自动加载。

维护者

名称GitLab 处理
Dillon Wheeler@dillonwheeler
Jeff Martin@jeffersonmartin

工作原理

此包的目的不是提供 Google Cloud API 中每个端点的功能。

我们采取了更简单的方法,提供了一个通用的 ApiClient,它可以对您在 Google API 文档中找到的任何端点执行 GETPOSTPUTPATCHDELETE 请求,并为您处理 API 响应、错误处理和分页。

这基于由 Guzzle HTTP 客户端提供的 Laravel HTTP 客户端的简洁性,为 Google API 响应提供“最后几行代码解析”,以改善开发人员体验。

我们对 GitLab Access Manager 经常使用的端点有额外的类和方法,我们将随着时间的推移对这些进行迭代。

安装

要求

要求版本
PHP>=8.0

添加 Composer 包

此包使用 日历版本控制

我们建议始终在您的 composer.json 文件中使用特定版本,并在假设最新版本适合您的项目之前,查看每个版本的 变更日志 中的破坏性更改。

composer require glamstack/google-cloud-sdk:2.5.25

如果您正在为此包做出贡献,请参阅 CONTRIBUTING 以获取配置带有符号链接的本地 composer 包的说明。

发布配置文件

php artisan vendor:publish --tag=glamstack-google-cloud

版本升级

如果您已升级到该软件包的新版本,您应该备份现有的配置文件,以避免您的自定义配置被覆盖。

cp config/glamstack-google-cloud.php config/glamstack-google-cloud.php.bak

php artisan vendor:publish --tag=glamstack-google-cloud

日历版本控制

GitLab IT 工程团队使用修改版的 日历版本控制(CalVer) 而不是 语义版本控制(SemVer)。CalVer 有 YY(例如,2021 => 21),但我们感觉版本 21.xx 不太直观。由于我们团队从 2021 年开始使用,我们决定只使用年份的最后一位整数(2021 => 1.x,2022 => 2.x,等等)。

版本号表示发布日期,格式为 vY.M.D

我们不使用语义版本控制的原因

  1. 我们持续向 main/master/production 发布,并在大多数版本中做出破坏性更改,因此对于语义向后兼容的版本号,对我们来说不太直观。
  2. 我们不希望讨论如何称呼我们的发布/里程碑,以及它是否是主要版本、次要版本还是修补程序版本。我们只是编写代码,编写变更日志,并在完成的那天发布。变更日志的发布日期成为标记的版本号(例如,2022-02-01v2.2.1)。我们可能对更大的版本号(例如,v2.2)进行参考,但这仅用于每月里程碑规划和规范目的。所有代码标签都包含发布日期(例如,v2.2.1)。
  3. 这使我们能够使用 GitLab CI/CD 自动化版本标记过程,基于管道作业运行的日期。
  4. 在计划更改窗口期间,我们无需担心与“保持最新版本”相关的差异和/或破坏性更改,即可更新使用此软件包的每个项目的 composer.json 文件到特定或新版本号。我们不维护任何分支或分歧分支。
  5. 我们的软件包使用您现有 Laravel 应用程序中的底层软件包,因此保持您的 Laravel 应用程序版本更新可以解决大多数安全问题。

初始化 SDK

API 客户端的初始化可以通过传递(字符串)连接密钥或传递(数组)连接配置来完成。

Google API 认证

该软件包使用 glamstack/google-auth-sdk 软件包来创建用于通过 Google JWT Web Token 认证与 Google Cloud API 端点

有关 glamstack/google-auth-sdk 的更多信息,请参阅 Google Auth SDK README.md

连接密钥

我们使用 连接密钥 的概念,它引用 config/glamstack-google-cloud.php 中的配置数组,允许您预先配置一个或多个 API 连接。

每个连接密钥都与 GCP 服务帐户 JSON 密钥相关联。这可以用来配置不同的认证范围连接和权限到您的 GCP 组织或不同的 GCP 项目(根据您使用的 API 调用)。这允许针对特定 API 调用进行最小权限,并且您还可以配置多个与同一 GCP 项目和具有不同权限级别的不同 API 令牌的连接。

示例连接密钥初始化

// Initialize the SDK using the `test` configuration from `glamstack-google-cloud.php`
$client = new Glamstack\GoogleCloud\ApiClient('test');

示例连接密钥配置

return [
    'connections' => [
        'test' => [
            'project_id' => env('GOOGLE_CLOUD_TEST_PROJECT_ID'),
            'api_scopes' => [
                'https://www.googleapis.com/auth/ndev.clouddns.readwrite'
            ],
            'json_key_file' => storage_path('keys/glamstack-google-cloud/test.json'),
            'log_channels' => ['single']
        ]
    ]
]

动态连接配置数组

如果您不想预先配置连接,而是希望动态使用存储在数据库中的连接变量,您可以通过传递一个数组来传入所需的配置(参见示例连接配置数组初始化),在ApiClient构造方法的第二个参数中使用connection_config数组。

所需参数

类型描述
api_scopes数组API所需使用的API作用域数组
project_id字符串在运行API调用的Google项目ID
json_key_file_path字符串选项1 - 提供一个指向.json密钥文件的路径
json_key字符串选项2 - 提供存储在数据库中的JSON密钥内容

在文件系统中使用JSON密钥文件

$client = new Glamstack\GoogleCloud\ApiClient(null, [
    'api_scopes' => ['https://www.googleapis.com/auth/ndev.clouddns.readwrite'],
    'json_key_file_path' => storage('keys/glamstack-google-cloud/gcp_project_1.json'),
    'project_id' => 'example-project-123'
]);

在数据库中使用JSON密钥字符串

安全警告:您永远不应该将服务帐户密钥(JSON内容)作为变量提交到源代码中,以避免泄露您的GCP组织或项目的凭据。

建议在加密之前将JSON密钥转换为base 64编码的字符串,因为这是GCP服务帐户API用于privateKeyData字段的格式。

// Get service account from your model (`GoogleServiceAccount` is an example)
$service_account = \App\Models\GoogleServiceAccount::where('id', '123456')->firstOrFail();

// Get JSON key string from database column that has an encrypted value
$json_key_string = decrypt(json_decode($service_account->json_key));

$client = new \Glamstack\GoogleCloud\ApiClient(null, [
    'api_scopes' => ['https://www.googleapis.com/auth/ndev.clouddns.readwrite'],
    'json_key' => $json_key_string,
    'project_id' => 'example-project-123'
]);

以下示例显示了存储在数据库中的JSON密钥值。

// Get service account from your model (`GoogleServiceAccount` is an example)
$service_account = \App\Models\GoogleServiceAccount::where('id', '123456')->firstOrFail();

dd(decrypt(json_decode($service_account->json_key));
// {
//     "type": "service_account",
//     "project_id": "project_id",
//     "private_key_id": "key_id",
//     "private_key": "key_data",
//     "client_email": "xxxxx@xxxxx.iam.gserviceaccount.com",
//     "client_id": "123455667897654",
//     "auth_uri": "https://#/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": "some stuff"
// }

端点

通用 REST 调用

您需要为每个使用的端点初始化API客户端并设置项目ID。

$project_id变量用于文档和教育目的。您还可以在URL中嵌入项目ID,而不是定义变量。

$client = new Glamstack\GoogleCloud\ApiClient('test');
$project_id = config('glamstack-google-cloud.connections.test.project_id');

GET 请求

示例:[https://cloud.google.com/compute/docs/reference/rest/v1/addresses/list](https://cloud.google.com/compute/docs/reference/rest/v1/addresses/list)

$response = $client->rest()->get('https://compute.googleapis.com/compute/v1/projects/' . $project_id . '/regions/us-central1/addresses', []);

示例:[https://cloud.google.com/compute/docs/reference/rest/v1/addresses/get](https://cloud.google.com/compute/docs/reference/rest/v1/addresses/get)

$resource_id = 'string';

$response = $client->rest()->get('https://compute.googleapis.com/compute/v1/projects/' . $project_id . '/regions/us-central1/addresses/' . $resource_id, []);

POST 请求

示例:[https://cloud.google.com/compute/docs/reference/rest/v1/addresses/insert](https://cloud.google.com/compute/docs/reference/rest/v1/addresses/insert)

$request_data = [
    'name' => 'string',
    'description' => 'string',
    'networkTier' => 'enum',
    'ipVersion' => 'enum',
    'addressType' => 'enum',
    'subnetwork' => 'string',
    'network' => 'string'
];

$response = $client->rest()->post('https://compute.googleapis.com/compute/v1/projects/' . $project_id . '/regions/us-central1/addresses', $request_data);

PATCH和PUT请求

某些PATCH请求使用字段掩码来提供要更新的字段列表。这可能需要根据API端点文档添加到$request_data数组中。

$resource_id = 'string';

// This is a different style of using variables that may be helpful for some
// resources that have a full URI returned with the `POST` method
$resource_uri = 'projects/' . $project_id . '/path/to/endpoint/' . $resource_id;

$request_data = [
    'description' => 'string',
];
$response = $client->rest()->patch('https://compute.googleapis.com/compute/v1/' . $resource_uri, $request_data);
$response = $client->rest()->put('https://compute.googleapis.com/compute/v1/' . $resource_uri, $request_data);

DELETE 请求

示例:[https://cloud.google.com/compute/docs/reference/rest/v1/addresses/delete](https://cloud.google.com/compute/docs/reference/rest/v1/addresses/delete)

$response = $client->rest()->delete('https://compute.googleapis.com/compute/v1/projects/' . config('glamstack-google-cloud.connections.test.project_id') . '/regions/us-central1/addresses/{resourceId}');

云DNS - 管理区域

查看API文档以了解更多信息。

$client = new Glamstack\GoogleCloud\ApiClient('test');

获取区域列表

$response = $client->dns()->managedZone()->list();

获取特定区域

$response = $client->dns()->managedZone()->get('testing-zone');

创建区域

$response = $client->dns()->managedZone()->create([
    'name' => 'testing-zone-3',
    'dns_name' => 'testing-zone-3.example.com.',
    'visibility' => 'private',
    'dnssec_config_state' => 'off',
    'description' => 'Testing zone 3 by SDK',
]);

删除区域

$response = $client->dns()->managedZone()->delete('testing-zone-3');

云DNS - 记录集

查看API文档以了解更多信息。

$client = new Glamstack\GoogleCloud\ApiClient('test');

获取记录列表

$response = $client->dns()->recordSet()->list('testing-zone');

获取特定记录

$response = $client->dns()->recordSet()->get(
    'testing-zone',
    'testingmail.testingzone.example.com.',
    'CNAME'
);

创建记录

$response = $client->dns()->recordSet()->create('testing-zone', [
    'name' => 'testingmail.testingzone.example.com.',
    'type' => 'CNAME',
    'ttl' => 300,
    'rrdatas' => ['mail.testingzone.example.com.']
    ]
);

删除记录

$response = $client->dns()->RecordSet()->delete(
    'testing-zone',
    'testingmail.testingzone.example.com.',
    'CNAME'
);

日志配置

默认情况下,我们使用在您的应用程序的config/logging.php文件中配置的single通道发送所有日志。这会将所有Google Cloud日志消息发送到storage/logs/laravel.log文件。

如果您希望将Google Cloud日志显示在单独的日志文件中,以便更容易地分类而不包含无关日志消息,您可以创建一个自定义日志通道。例如,我们建议使用glamstack-google-cloud的值,但您可以选择任何您喜欢的名称。

将自定义日志通道添加到config/logging.php

创建日志通道

    'channels' => [

        // Add anywhere in the `channels` array

        'glamstack-google-cloud' => [
            'name' => 'glamstack-google-cloud',
            'driver' => 'single',
            'level' => 'debug',
            'path' => storage_path('logs/glamstack-google-cloud.log'),
        ],
    ],

更新channels.stack.channels数组以包括自定义通道的数组键(例如glamstack-google-cloud)。请确保将glamstack-google-cloud添加到现有数组值中,而不是替换现有值。

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['single','slack','glamstack-google-cloud'],
            'ignore_exceptions' => false,
        ],
    ],

安全最佳实践

Google API作用域

与软件包一起加载的默认配置文件展示了API作用域配置的示例。请务必遵循最小权限原则。所有Google作用域都可以在这里找到:这里

您可以通过参考特定REST端点的Google API Explorer文档来了解更多关于所需授权作用域的信息。

JSON密钥存储

请不要将JSON密钥文件存储在未包含在.gitignore文件中的任何位置。这是为了避免将您的凭证提交到您的存储库(秘密泄露)

建议将每个JSON API密钥的副本存储在您首选的密码管理器(例如1Password,LastPass等)和/或秘密库(例如HashiCorp Vault,Ansible等)中。

日志输出

有效

[2022-05-10 15:44:58] testing.INFO: Glamstack\GoogleCloud\Resources\BaseClient::GETREQUEST 200 https://dns.googleapis.com/dns/v1/projects/example-project/managedZones/testing-zone/rrsets/testingexample.testingzone.example.com./CNAME {"api_endpoint":"https://dns.googleapis.com/dns/v1/projects/example-project/managedZones/testing-zone/rrsets/testingexample.testingzone.example.com./CNAME","api_method":"GLAMSTACK\\GOOGLECLOUD\\RESOURCES\\BASECLIENT::GETREQUEST","class":"Glamstack\\GoogleCloud\\Resources\\BaseClient","event_type":"google-cloud-api-response-info","message":"Glamstack\\GoogleCloud\\Resources\\BaseClient::GETREQUEST 200 https://dns.googleapis.com/dns/v1/projects/example-project/managedZones/testing-zone/rrsets/testingexample.testingzone.example.com./CNAME","status_code":200}

认证失败

[2022-05-09 16:45:07] testing.INFO: Google OAuth2 Authentication Failed {"calling_method":"__CONSTRUCT","class":"Glamstack\\GoogleCloud\\Resources\\BaseClient","event_type":"google-auth-api-response-info","message":"Google OAuth2 Authentication Failed"}

测试套件

此SDK使用Pest框架编写的功能和单元测试。

运行测试

您可以从项目目录中运行SDK中的所有测试。

cd ~/Sites/google-cloud-sdk
./vendor/bin/pest

或者,您可以使用内置的composer命令来运行测试。

composer test

您还可以使用覆盖率报告来运行测试。

composer test-coverage

问题跟踪和错误报告

请访问我们的问题跟踪器并创建一个问题或对现有问题进行评论。

贡献

有关如何贡献的更多信息,请参阅CONTRIBUTING.md