🚀

Cloud Functions(Google Cloud)でAWS SDKを実行する

2021/09/27に公開

はじめに

先日、Cloud Functionsを使ったツールを作成する機会があり、その際に得られた知見をまとめてみました。(Google Cloud初心者向けの内容です。)

はじめに、それぞれのサービスやツールを簡単に説明します。

Cloud Functionsとは

https://cloud.google.com/functions

  • イベント駆動なサーバレスプラットフォームです。
  • Function as a Service(FaaS)として、Google Cloudの中ではポピュラーなサービスです。
  • AWSで言うところのLambdaに相当します。
  • 本記事内にあるようにデプロイさえできれば、あとはエンドポイントを指定して実行できます。

Secret Managerとは

https://cloud.google.com/secret-manager

  • 安全に機密情報を管理することができる、Google Cloudの1サービスです。
  • Cloud IAMによって明示的にアクセスを管理することができます。
  • AWSにもAWS Secrets Managerと言うサービスが有り、類似した機能が提供されています。

AWS SDK for Python (Boto3)とは

https://aws.amazon.com/jp/sdk-for-python/

やりたいこと

本記事ではCloud Functionsのサンプルとして、ハイブリッドクラウドなユースケースを考えます。
具体的には、Cloud FunctionsからSecret Manager経由でAWSの認証情報を取得して、Boto3により最終的になんらかのAWSサービスに関連した処理を実行します。

事前準備

gcloudコマンドのインストール

あらかじめCloud SDK(gcloudコマンド)を用意しておきます。
以下のページの手順に従って下さい。
https://cloud.google.com/sdk/docs/install?hl=JA
念のため正常にインストールされたかを確認しておきます。

$ gcloud version | head -n 1
Google Cloud SDK 354.0.0

APIの有効化

また、Google Cloudを各サービスを利用するにはコンソール画面から各サービスのAPIを有効化しておく必要があります。
もしそのプロジェクトで初めてGoogle Cloudのサービス使うのであれば、本記事で使用する以下の2つのAPIを有効化して下さい。それぞれコンソール画面から該当のサービスを開いてワンクリックで済みます。

  • Cloud Functions API
  • Secret Manager API

さらに、Cloud Functionsは暗黙的にCloud StorageとCloud Buildを利用しているようなので、その2つも有効化を求められる場合があります。ご注意下さい。

  • Cloud Storage API
  • Cloud Build API

やってみた in Python

サンプルコード

main.py
from google.cloud import secretmanager
import boto3
import os


def main(request):
    aws_access_key_id = get_secret('sec_aws_access_key_id')
    aws_secret_access_key = get_secret('sec_aws_secret_access_key')

    request_json = request.get_json()
    target_environment = request_json['environment']

    return(aws_action(
        aws_access_key_id,
        aws_secret_access_key,
        target_environment,
    ))


def get_secret(secret_name):
    '''
    Secret Managerから最新の情報を取得する
    '''
    client = secretmanager.SecretManagerServiceClient()
    gcp_project_id = os.environ.get('GCP_PROJECT', 'GCP Project ID')
    name = f"projects/{gcp_project_id}/secrets/{secret_name}/versions/{'latest'}"
    response = client.access_secret_version(request={"name": name})

    return(response.payload.data.decode('UTF-8'))


def aws_action(access_key_id, secret_access_key, env):
    '''
    認証情報を使用してAWSのfoo-barサービスを使った何らかの処理を実行する
    '''
    client = boto3.client('foo-bar',
                          aws_access_key_id=access_key_id,
                          aws_secret_access_key=secret_access_key,
                          region_name='ap-northeast-1')
    # ... snip ...
    # ここにBoto3で実行したい処理を記述します。
    # ... snip ...
    
    return


if __name__ == '__main__':
    main()
requirement.txt
google-cloud-secret-manager
boto3

解説

main関数

  • 予めコンソール等でsec_aws_access_key_idsec_aws_secret_access_keyの2つをSecretに登録しておく必要があります。
  • リクエストのボディからJSON形式で情報を取り出し、environmentパラメータを利用しています。この記事の本筋ではありませんが、便利なハックなので紹介の意味で書きました。(動作テストを行う目的であれば不要です。)

get_secret関数

  • 上記のようにするとgcp_project_idは、環境変数から読み取ることも可能です。取得可能な予約済みの環境変数についてはこちらのリストが参考になります。
  • Secretのバージョンは基本的には最新のみを取得したいため、明示的に最新バージョンのエイリアスlatestを指定しています。

Cloud Functionsデプロイ

gcloudコマンドを利用して、ローカル環境から以下のようにデプロイできます。
関数名はdeployサブコマンドの後に続けて指定します。(ここではCloudFunctions-To-AWS

deploy-cloud-functions.sh
#!/bin/bash
SERVICE_ACCOUNT="foo@bar.gserviceaccount.com"

gcloud functions deploy CloudFunctions-To-AWS \
    --region=asia-northeast1 \
    --source=./cloud-functions \
    --service-account=${SERVICE_ACCOUNT} \
    --entry-point=main \
    --runtime=python37 \
    --security-level=secure-always \
    --trigger-http

解説

  • サービスアカウントは予め用意したものを設定する必要があります(後述)
  • --sourceにはpythonコードのディレクトリを指定します。
  • --entry-pointはkickするPythonコードの関数名です。
  • --security-levelにはsecure-alwaysを指定しており、HTTPSを必須としています。
  • デプロイに際してのデバッグでは--verbosity=debugを追加する方法が便利です。

補足

Cloud Functionsをデプロイする際、初回のデプロイでは以下のメッセージが表示されます。

Allow unauthenticated invocations of new function [CloudFunctions-To-AWS]?
 (y/N)?  

多くの場合では認証を求める設定としたいと思いますので、その場合には必ずNを選択します。

おわりに

最後まで読んでいただき、ありがとうございます。

実際に上記のサンプルを動かすにはサービスアカウントの適切な設定が必要となりますが、それについてはやや煩雑なため、別途記事を書きました。
SecretManagerにアクセスできるサービスアカウントを設定する - Zenn

しかし、サービスアカウントの設定を除いた本記事の内容だけであれば「思ったよりもシンプルに実装できそう」と感じて頂けたのでは無いでしょうか。

どなたかに届けば幸いです。

参考文献

https://cloud.google.com/functions/docs/writing/http#writing_http_helloworld-python
https://cloud.google.com/secret-manager/docs/samples/secretmanager-access-secret-version
https://medium.com/google-cloud-jp/cloud-functions-basic-cd18686f0198

Discussion