キーを使用せずに AWS から Google Cloud にアクセスする方法

記事タイトルとURLをコピーする

G-gen の藤岡です。当記事では、 Workload Identity 連携を使う ことで Amazon Web Services(以下 AWS)の EC2 から Google Cloud(旧称 GCP)の Cloud Storage(以下 GCS)への操作を サービスアカウントキーを発行せず に実現する方法を紹介します。

なお、Google Cloud 側の設定は Terraform を使用します。

概要

マルチクラウドなど複数のプラットフォームから Google Cloud APIs を呼び出し、認証が必要な場合にサービスアカウントキーを発行することがあります。しかしサービスアカウントキーは有効期限が長く、漏洩した際に危険が伴います。また、キーのローテーションなど運用負荷がかかります。

そこで、当記事では Workload Identity 連携を使うことで、サービスアカウントキーを発行せず に AWS の EC2 から Google Cloud の GCS を操作する方法について紹介します。

Google Cloud APIs について詳しく知りたい方は以下の記事をご参照ください。

blog.g-gen.co.jp

まず、当記事で利用するサービスについて紹介します。

Workload Identity 連携とは

Workload Identity 連携 は、オンプレミスや AWS 等の外部 ID プロバイダ(IdP)と連携をし、Google Cloud のリソースを呼び出します。オンプレミスや AWS のワークロードはセキュリティトークンサービス(STS)エンドポイントを呼び出し、IdP から取得した認証トークンを有効期限が短い Google Cloud アクセストークン と交換します。

この Google Cloud アクセストークンを使ってワークロードは サービスアカウントになりすまして Google Cloud のリソースにアクセスできる ようになります。

当記事で紹介する構成では、認証・認可の流れは以下のようになっています。

構成図

なお、AWS の一時的なセキュリティ認証情報を生成するために、IAM ロールの AssumeRole を使用しています。

サービスアカウントキーと Workload Identity の認証情報

前述の通り、サービスアカウントキーの発行にはセキュリティリスクが伴います。そこで、実際にサービスアカウントキーと Workload Identity の認証情報を比べることでどのようなリスクがあるのか見ていきます。

まず、サービスアカウントキーの json ファイルの内容は以下のようになっています。

{
  "type": "service_account",
  "project_id": "<プロジェクト ID>",
  "private_key_id": "f20bce38bbbe5c38cbbb5ceb0ee768c84ff15388",
  "private_key": "-----BEGIN PRIVATE KEY-----
<秘密鍵>",
  "client_id": "<OAuth 2 クライアント ID>",
  "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/aws-sa%40<プロジェクト ID>.iam.gserviceaccount.com"
}

次に、Workload Identity の認証情報の内容は以下のようになっています。

{
  "type": "external_account",
  "audience": "//iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/aws-id-pool-1/providers/aws-provider",
  "subject_token_type": "urn:ietf:params:aws:token-type:aws4_request",
  "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/aws-sa@<プロジェクト ID>.iam.gserviceaccount.com:generateAccessToken",
  "token_url": "https://sts.googleapis.com/v1/token",
  "credential_source": {
    "environment_id": "aws1",
    "region_url": "http://169.254.169.254/latest/meta-data/placement/availability-zone",
    "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials",
    "regional_cred_verification_url": "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15"
  }
}

サービスアカウントキーには、 private_key秘密鍵が含まれています 。サービスアカウントキーが漏洩した場合、 Google Cloud 環境にあるデータは攻撃者によって取得される可能性があります。例えば、サービスアカウントにインスタンス起動の権限がある場合に、攻撃者によって大量のインスタンスが作成され多額の利用料金が請求される等の恐れがあります。

Workload Identity の認証情報には 秘密鍵は含まれておらず、Workload Identity プールで指定したプロバイダおよびアカウントからのみ この認証情報を使用してリソースにアクセスが可能です。今回はプロバイダに AWS を指定しているため、 "environment_id": "aws1" となっています。

実施内容

前述の通り、Google Cloud 側の設定は Terraform を使用します。テンプレートは後述の「Terraform テンプレート全体像」を1つの main.tf として実行しますが、テンプレートのブロックごとに解説を行います。そのため、 Terraform の解説が不要な方は「Google Cloud の設定(Terraform 解説)」はスキップしてください。

構成図

改めて、今回実施する構成は以下のとおりです。

構成図

Terraform テンプレート全体像

実行するテンプレートは以下の通りです。プロジェクト ID 等は適宜書き換えてください。

## Terraform の初期設定
# local 定義
locals {
  project_id     = "<プロジェクト id>"
  project_number = "<プロジェクト番号>"
  
  # api 有効化用
  services = toset([                       # Workload Identity 連携用
    "iam.googleapis.com",                  # IAM
    "cloudresourcemanager.googleapis.com", # Resource Manager
    "iamcredentials.googleapis.com",       # Service Account Credentials
    "sts.googleapis.com"                   # Security Token Service API
  ])
  
  # workload identity provider 用
  aws_id = "<aws アカウント id>"
}
  
  
# provider / state ファイル設定
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 4.0.0"
    }
  }
  required_version = ">= 1.3.0"
  
  backend "gcs" {
    bucket = "fujioka_bucket_tfstate"
    prefix = "terraform/state"
  }
}
  
  
## API の有効化(workload identity 用)
resource "google_project_service" "enable_api" {
  for_each                   = local.services
  project                    = local.project_id
  service                    = each.value
  disable_dependent_services = true # destroy 時に依存サービスも無効化
}
  
  
## サービスアカウント
# 作成
resource "google_service_account" "aws_sa" {
  project      = local.project_id
  account_id   = "aws-sa"
  display_name = "aws 用サービスアカウント"
}
  
# 権限付与
resource "google_project_iam_member" "aws_sa_role" {
  project = local.project_id
  role    = "roles/storage.admin"
  member  = "serviceAccount:${google_service_account.aws_sa.email}"
}
  
  
## workload identity 設定
# id プール作成
resource "google_iam_workload_identity_pool" "aws_id_pool" {
  project                   = local.project_id
  workload_identity_pool_id = "aws-id-pool-1"
  display_name              = "aws_id_pool"
  description               = "aws 用プール"
}
  
# プールにプロバイダ追加
resource "google_iam_workload_identity_pool_provider" "aws_provider" {
  workload_identity_pool_id          = google_iam_workload_identity_pool.aws_id_pool.workload_identity_pool_id
  workload_identity_pool_provider_id = "aws-provider"
  display_name                       = "aws_provider"
  description                        = "aws 用プロバイダ設定"
  aws {
    account_id = local.aws_id
  }
}
  
# workload identity プロバイダ(aws)がサービスアカウントの権限借用ができるようにする
resource "google_service_account_iam_binding" "aws_sa_role_binging" {
  service_account_id = google_service_account.aws_sa.name
  role               = "roles/iam.workloadIdentityUser"
  
  members = [
    "principalSet://iam.googleapis.com/projects/${local.project_number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.aws_id_pool.workload_identity_pool_id}/*",  # workload identity プール内のすべての外部 id
  ]
}

事前準備

なお、当記事では Terraform の概要等について触れないため、コマンドや tfstate ファイル等については以下の記事をご参照ください。 blog.g-gen.co.jp

tfstate ファイル用 GCS バケットの作成

tfstate ファイルを保存するためのバケットを手動で作成します。

tfstate 用バケット

Google Cloud の設定(Terraform 解説)

それでは、テンプレートのブロックごとに解説を行っていきます。

Terraform の初期設定

local で変数を定義、provider の設定をします。

## Terraform の初期設定
# local 定義
locals {
  project_id     = "<プロジェクト id>"
  project_number = "<プロジェクト番号>"
  
  # api 有効化用
  services = toset([                       # Workload Identity 連携用
    "iam.googleapis.com",                  # IAM
    "cloudresourcemanager.googleapis.com", # Resource Manager
    "iamcredentials.googleapis.com",       # Service Account Credentials
    "sts.googleapis.com"                   # Security Token Service API
  ])
  
  # workload identity provider 用
  aws_id = "<aws アカウント id>"
}
  
  
# provider / state ファイル設定
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 4.0.0"
    }
  }
  required_version = ">= 1.3.0"
  
  backend "gcs" {
    bucket = "fujioka_bucket_tfstate"
    prefix = "terraform/state"
  }
}

API の有効化

Workload Identity 連携で 必要な API を有効化します。local で定義している services が入ります。

## API の有効化(workload identity 用)
resource "google_project_service" "enable_api" {
  for_each                   = local.services
  project                    = local.project_id
  service                    = each.value
  disable_dependent_services = true # destroy 時に依存サービスも無効化
}

サービスアカウントの作成 / 権限付与

今回は EC2 から GCS バケットの作成、削除、オブジェクトの作成を行うため、Storage 管理者roles/storage.admin)の権限を付与します。

## サービスアカウント
# 作成
resource "google_service_account" "aws_sa" {
  project      = local.project_id
  account_id   = "aws-sa"
  display_name = "aws 用サービスアカウント"
}
  
# 権限付与
resource "google_project_iam_member" "aws_sa_role" {
  project = local.project_id
  role    = "roles/storage.admin"
  member  = "serviceAccount:${google_service_account.aws_sa.email}"
}

Workload Identity の設定

コンソールや gcloud コマンドで Workload Identity 連携の設定する場合は ドキュメント の通りです。今回は principalSet://〜 でマッピングをプール内の全ての外部 ID としていますが、マッピングを AWS の特定の IAM ロールに絞ることも可能です。

外部 ID にサービスアカウントの権限借用を許可 するには Workload Identity ユーザーロールroles/iam.workloadIdentityUser)を付与します。

## workload identity 設定
# id プール作成
resource "google_iam_workload_identity_pool" "aws_id_pool" {
  project                   = local.project_id
  workload_identity_pool_id = "aws-id-pool-1"
  display_name              = "aws_id_pool"
  description               = "aws 用プール"
}
  
# プールにプロバイダ追加
resource "google_iam_workload_identity_pool_provider" "aws_provider" {
  workload_identity_pool_id          = google_iam_workload_identity_pool.aws_id_pool.workload_identity_pool_id
  workload_identity_pool_provider_id = "aws-provider"
  display_name                       = "aws_provider"
  description                        = "aws 用プロバイダ設定"
  aws {
    account_id = local.aws_id
  }
}
  
# workload identity プロバイダ(aws)がサービスアカウントの権限借用ができるようにする
resource "google_service_account_iam_binding" "aws_sa_role_binging" {
  service_account_id = google_service_account.aws_sa.name
  role               = "roles/iam.workloadIdentityUser"
  
  members = [
    "principalSet://iam.googleapis.com/projects/${local.project_number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.aws_id_pool.workload_identity_pool_id}/*",  # workload identity プール内のすべての外部 id
  ]
}

Terraform テンプレートの解説は以上です。

Terraform の実行

それでは、「Terraform テンプレート全体像」に記載の main.tf を Google Cloud 環境に適用していきます。今回は Cloud Shell から実行します。

まず terraform init で初期化をします。

fujioka@cloudshell:~/terraform-demo (xxxx)$ terraform init
  
Initializing the backend...
  
Successfully configured the backend "gcs"! Terraform will automatically
use this backend unless the backend configuration changes.
〜略〜
Terraform has been successfully initialized!
〜略〜
fujioka@cloudshell:~/terraform-demo (xxxx)$

初期化することで backend で指定した fujioka_bucket_tfstate/terraform/statedefault.tfstate が作成されます。

tfstate ファイル

次に terraform plan でドライランをします。Plan: 9 to add, 0 to change, 0 to destroy. とあるように、今回は9つのリソースが作成されます。

fujioka@cloudshell:~/terraform-demo (xxxx)$ terraform plan
  
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
  
Terraform will perform the following actions:
~省略~
Plan: 9 to add, 0 to change, 0 to destroy.
  
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
fujioka@cloudshell:~/terraform-demo (xxxx)$

terraform apply を実行し、 実環境に適用します。Apply complete! Resources: 9 added, 0 changed, 0 destroyed. と表示されれば成功です。

fujioka@cloudshell:~/terraform-demo (xxxx)$ terraform apply
  
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
  
Terraform will perform the following actions:
~省略~
Plan: 9 to add, 0 to change, 0 to destroy.
  
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.
  
  Enter a value: yes
~省略~
Apply complete! Resources: 9 added, 0 changed, 0 destroyed.
fujioka@cloudshell:~/terraform-demo (xxxx)$

コンソール画面から各リソースが作成されていることがわかります。

サービスアカウント
Workload Identity プール

Workload Identity の認証情報のダウンロード

Google Cloud コンソールで [IAM と管理] > [Workload Identity 連携] > [作成したプール] > [接続済みサービスアカウント] > [ダウンロード] をクリックします。

Workload Identity の認証情報のダウンロード①

[プロバイダ] には Terraform の google_iam_workload_identity_pool_provider で設定をした aws_provider を設定し、[構成をダウンロード] をクリックします。

Workload Identity の認証情報のダウンロード②

clientLibraryConfig-aws-provider.json がローカルにダウンロードされます。この Workload Identity の認証情報の内容については前述しているため、ここでは割愛します。

AWS の設定

次に AWS の環境を設定していきます。

IAM ロールの作成

信頼されたエンティティを選択 で以下のように設定します。

項目 設定値
信頼されたエンティティタイプ AWS のサービス
ユースケース EC2

他の設定は ロール名 のみ入力をし、ポリシーはアタッチせずに作成します。ロール名は role-demo とします。

ロールの信頼関係は以下のようになります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

EC2 インスタンスの作成

インスタンスの詳細な設定についての説明はしませんが、今回はコンソールから名前のみを入力し、他はデフォルト設定でインスタンスを作成しました。インスタンス名は ec2-demo とします。

OS 情報は以下の通りです。

[ec2-user@ip-172-31-40-201 ~]$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
[ec2-user@ip-172-31-40-201 ~]$ 

EC2 に IAM ロールをアタッチ

インスタンス(ec2-demo)に前述の IAM ロールの作成 で作成した role-demo をアタッチします。

ロールをアタッチ

Google Cloud CLI のインストール

インスタンスで gcloud コマンドを使えるようにするために ドキュメント を参考に Google Cloud CLI をインストールします。

# パッケージのダウンロード
[ec2-user@ip-172-31-40-201 ~]$ curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-410.0.0-linux-x86_64.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  156M  100  156M    0     0  89.1M      0  0:00:01  0:00:01 --:--:-- 89.1M
[ec2-user@ip-172-31-40-201 ~]$ 
  
  
# 展開
[ec2-user@ip-172-31-40-201 ~]$ tar -xf google-cloud-cli-410.0.0-linux-x86_64.tar.gz 
[ec2-user@ip-172-31-40-201 ~]$ 
  
  
# gcloud CLI をパスに追加
[ec2-user@ip-172-31-40-201 ~]$ ./google-cloud-sdk/install.sh
Welcome to the Google Cloud CLI!
~省略~
Do you want to help improve the Google Cloud CLI (y/N)?  N
~省略~
Modify profile to update your $PATH and enable shell command completion?
  
Do you want to continue (Y/n)?  Y
  
The Google Cloud SDK installer will now prompt you to update an rc file to bring the Google Cloud CLIs into your environment.
  
Enter a path to an rc file to update, or leave blank to use [/home/ec2-user/.bashrc]:  
Backing up [/home/ec2-user/.bashrc] to [/home/ec2-user/.bashrc.backup].
[/home/ec2-user/.bashrc] has been updated.
~省略~
[ec2-user@ip-172-31-40-201 ~]$ 
  
  
# インスタンスに再接続をし、gcloud CLI がインストールされていることを確認
[ec2-user@ip-172-31-40-201 ~]$ gcloud version
Google Cloud SDK 410.0.0
bq 2.0.81
bundled-python3-unix 3.9.12
core 2022.11.11
gcloud-crc32c 1.0.0
gsutil 5.16
[ec2-user@ip-172-31-40-201 ~]$ 
  
  
# gcloud CLI の初期化
[ec2-user@ip-172-31-40-201 ~]$ gcloud init
  
  
# アカウントとプロジェクトが設定されていることを確認
[ec2-user@ip-172-31-40-201 ~]$ gcloud config configurations list
NAME     IS_ACTIVE  ACCOUNT              PROJECT         COMPUTE_DEFAULT_ZONE  COMPUTE_DEFAULT_REGION
default  True       fujioka@g-gen.co.jp  <プロジェクト ID>
[ec2-user@ip-172-31-40-201 ~]$ 

Workload Identity 連携を使用して認証

ローカルにダウンロードした Workload Identity の認証情報をインスタンスに設置します。

[ec2-user@ip-172-31-40-201 ~]$ cat clientLibraryConfig-aws-provider.json 
{
  "type": "external_account",
  "audience": "//iam.googleapis.com/projects/<プロジェクト番号>/locations/global/workloadIdentityPools/aws-id-pool-1/providers/aws-provider",
  "subject_token_type": "urn:ietf:params:aws:token-type:aws4_request",
  "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/aws-sa@<プロジェクト ID>.iam.gserviceaccount.com:generateAccessToken",
  "token_url": "https://sts.googleapis.com/v1/token",
  "credential_source": {
    "environment_id": "aws1",
    "region_url": "http://169.254.169.254/latest/meta-data/placement/availability-zone",
    "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials",
    "regional_cred_verification_url": "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15"
  }
}
[ec2-user@ip-172-31-40-201 ~]$ 

Workload Identity 連携を使用して認証します。gcloud auth login で上記で設置したファイルを指定します。

# Workload Identity 連携を使用して認証
[ec2-user@ip-172-31-40-201 ~]$ gcloud auth login --cred-file=clientLibraryConfig-aws-provider.json
  
Authenticated with external account credentials for: [aws-sa@<プロジェクト ID>.iam.gserviceaccount.com].
Your current project is [<プロジェクト ID>].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID
[ec2-user@ip-172-31-40-201 ~]$ 
  
# サービスアカウントとプロジェクトが設定されていることを確認
[ec2-user@ip-172-31-40-201 ~]$ gcloud config configurations list
NAME     IS_ACTIVE  ACCOUNT                                        PROJECT         COMPUTE_DEFAULT_ZONE  COMPUTE_DEFAULT_REGION
default  True       aws-sa@<プロジェクト ID>.iam.gserviceaccount.com  <プロジェクト ID>
[ec2-user@ip-172-31-40-201 ~]$ 

GCS の操作

ここでは GCS で以下の操作を順に実行および確認します。

  1. バケットの作成
  2. オブジェクトのアップロード
  3. バケットの削除

まず、バケットの作成をします。

# 1. バケットの作成
[ec2-user@ip-172-31-40-201 ~]$ gcloud storage buckets create gs://bucket-demo-2023
Creating gs://bucket-demo-2023/...
[ec2-user@ip-172-31-40-201 ~]$ 

gcloud storage ls でバケットを一覧表示できます。Terraform の tfstate ファイル用のバケットも表示されています。

[ec2-user@ip-172-31-40-201 ~]$ gcloud storage ls
gs://bucket-demo-2023/
gs://fujioka_bucket_tfstate/
[ec2-user@ip-172-31-40-201 ~]$ 

次に、任意のオブジェクトをアップロードします。

# 2. オブジェクトのアップロード
[ec2-user@ip-172-31-40-201 ~]$ gcloud storage cp file-demo gs://bucket-demo-2023/
Copying file://file-demo to gs://bucket-demo-2023/file-demo
  Completed files 1/1 | 5.0B/5.0B                                                                                                                                                                                 
[ec2-user@ip-172-31-40-201 ~]$ 

--recursive オプションを付けることで、バケット内のオブジェクトを確認できます。

[ec2-user@ip-172-31-40-201 ~]$ gcloud storage ls --recursive gs://bucket-demo-2023/**
gs://bucket-demo-2023/file-demo
[ec2-user@ip-172-31-40-201 ~]$ 

最後に、作成したバケットを削除します。

# 3. バケットの削除(オブジェクトとバケットを削除)
[ec2-user@ip-172-31-40-201 ~]$ gcloud storage rm --recursive gs://bucket-demo-2023/
Removing objects:
Removing gs://bucket-demo-2023/file-demo#1673232446429799...
Completed 1/1    
  
Removing Buckets:
Removing gs://bucket-demo-2023/...
Completed 1/1  
[ec2-user@ip-172-31-40-201 ~]$ 

再度バケットを一覧表示すると、bucket-demo-2023 バケットが削除されていることがわかります。

[ec2-user@ip-172-31-40-201 ~]$ gcloud storage ls
gs://fujioka_bucket_tfstate/
[ec2-user@ip-172-31-40-201 ~]$ 

環境の削除

AWS

今回は作成した以下のリソースを削除します。

  • EC2
  • IAM ロール

Google Cloud

terraform destroy コマンドで環境を削除します。Destroy complete! Resources: 9 destroyed. と表示され、今回作成したリソース9つが削除されました。

fujioka@cloudshell:~/terraform-demo (xxxx)$ terraform destroy
~省略~
Plan: 0 to add, 0 to change, 9 to destroy.
  
Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.
  
  Enter a value: yes
~省略~
Destroy complete! Resources: 9 destroyed.
fujioka@cloudshell:~/terraform-demo (xxxx)$

注意点

Workload Identity プールは削除後、 30日間は復元が可能 です。コンソールからは [IAM と管理] > [Workload Identity 連携] から削除したプールとプロバイダを表示する を切り替えることで復元可能なプールが表示されます。

復元可能なプール

そのため、環境を削除後に、Terraform テンプレートを再実行すると terraform plan は通りますが、terraform apply で以下のように Requested entity already exists のエラーが表示されます。

│ Error: Error creating WorkloadIdentityPool: googleapi: Error 409: Requested entity already exists
│
│   with google_iam_workload_identity_pool.aws_id_pool,
│   on main.tf line 68, in resource "google_iam_workload_identity_pool" "aws_id_pool":
│   68: resource "google_iam_workload_identity_pool" "aws_id_pool" {
│
╵

プールが完全削除される30日以内に Terraform を再実行する場合は、google_iam_workload_identity_poolworkload_identity_pool_id を変更する必要があります。

藤岡 里美 (記事一覧)

クラウドソリューション部

数年前までチキン売ったりドレスショップで働いてました!2022年9月 G-gen にジョイン。ハイキューの映画を4回は見に行きたい。

Google Cloud All Certifications Engineer / Google Cloud Partner Top Engineer 2024