Powershellの標準コマンドだけを使ってGoogle Cloudに接続する方法
投稿者:今井
はじめに
こんにちは。CI部の今井です。
このテックブログでは、Google Cloud SDKを使用せずに、Powershellの標準コマンドとGoogle Cloud APIを使用して、Google Cloudに接続する方法を説明します。
この記事の方法を利用することでGoogle Cloud SDKをインストールせずに、Powershellの標準コマンドとAPIを使うことで、より柔軟な環境でGoogle Cloudに接続できるようになります。また、この方法がどのような場面で役立つかを理解することができます。
なかなかにニッチな内容となりますので、先にどういった方が対象となるかを以下に列挙させていただきます。想定している対象者は外部ライブラリを導入することができないWindows端末でGoogle Cloudへ接続しなければならないような要件を抱えている方となりますが、もしご参考になる方がいれば幸いです。
- ネットワークに接続できるWindows端末を利用している
- Google Cloud SDKをインストールすることができない
- 秘密鍵を利用することはできる(端末に保存することはできる)
- Powershellを利用することができる(検証で利用したPowershellのバージョンは5.1.19041.2673です)
準備
今回のテックブログではいくつかの準備が必要となります。以下に列挙させていただきますのでご確認ください。
- Google Cloudのプロジェクトの用意
- Google Cloudでサービスアカウントを作成し、ロールを付与
- 作成したサービスアカウントの秘密鍵を作成し、ローカル環境にダウンロード
- Google Cloudで今回利用するAPIを有効にする
今回のテックブログでは1番目のプロジェクトの作成については説明しません。他のテックブログをご参考にプロジェクトをご準備ください。
2番目のサービスアカウントの作成についてはサイドメニューの「IAMと管理」の中にあるサービスアカウントというところから作成してください。今回はCloud Storageのファイルをダウンロードするまでを行うため、該当のバケットの権限メニューでロールを付与してください。付与するロールとしては「Storageオブジェクト管理者」としています。
3番目の作成したサービスアカウントの秘密鍵を作成し、ローカル環境にダウンロードについては作成したサービスアカウントの詳細画面から行います。鍵の作成を押した後にダイアログが出てくると思いますので、P12形式の秘密鍵を作成するようにしてください。秘密鍵が作成されると秘密鍵のパスワードが表示されます。このパスワードは後ほど利用するため手元に残しておくようにしてください。
4番目のGoogle Cloudで今回利用するAPIを有効にするについては、サイドメニュー内の「API とサービス」の中にある有効なAPI とサービスから有効にしてください。今回はCloud StorageとCloud Storage APIを利用するため、この二つが有効になっていることを確認してください。
これで準備としてはほぼ完了になります。今回のテックブログではCloud Storageからファイルをダウンロードするところまで行うと説明していたので、一応テキストファイルの準備を以下のようにしておきました。バケット名とファイル名を後続の処理で利用するため、メモしておくようにします。
これで、すべての準備が完了しました!次のセクションではPowershellで作成したPowershellスクリプトについて説明します。
作成したPowershellスクリプト
今回作成したPowershellスクリプトはGoogleの公式ドキュメントに記載されている内容を参考に作成しています。こちらの記事では以下の順番で認証トークンを作成した後にその認証トークンを利用してGoogle CloudのAPIを呼び出すようにします。
サーバー間アプリケーションに OAuth 2.0 を使用する – 承認済み API 呼び出しの準備
- ヘッダー、クレームセット、署名を含む JSON Web Token(JWT、発音)を作成します。
- Google OAuth 2.0 認可サーバーにアクセス トークンをリクエストします。
- 承認サーバーが返す JSON レスポンスを処理します。
上記の内容を参考にして作成したものが以下のコードとなります。Powershellスクリプトをあまり書かないため視認性が悪かったりお作法ができていない部分もあるかと思いますが、ご容赦いただけますと幸いです。
# スクリプトの格納されているフォルダのパス
$script_folder_path= Split-Path $MyInvocation.MyCommand.path
# 秘密鍵の準備
$privateKeyPath = $script_folder_path + "\gc_private_key.p12"
$password = ConvertTo-SecureString "Password" -AsPlainText -Force
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($privateKeyPath, $password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
# 認証トークンの有効期限を設定
$JWT_EXPIRY=3600
$IAT=(Get-Date).ToUniversalTime().Subtract((Get-Date "1970-01-01")).TotalSeconds
$EXP=$IAT+$JWT_EXPIRY
# JWTのヘッダーの形成
$jwtHeader = "{""alg"":""RS256"",""typ"":""JWT""}"
$jwtHeaderByte = ([System.Text.Encoding]::Default).GetBytes($jwtHeader)
$jwtHeaderBase64 = [Convert]::ToBase64String($jwtHeaderByte)
# BASE64をBASE64URLに変更
$jwtHeaderBase64 = $jwtHeaderBase64.Replace('+','-')
$jwtHeaderBase64 = $jwtHeaderBase64.Replace('/','_')
$jwtHeaderBase64 = $jwtHeaderBase64.Replace('=','')
# JWTのクレームセットを作成
$jwtClaim = "{""iss"":""sa@gcproject.iam.gserviceaccount.com"",""scope"":""https://www.googleapis.com/auth/cloud-platform"",""aud"":""https://oauth2.googleapis.com/token"",""exp"":$EXP,""iat"":$IAT}"
$jwtClaimByte = ([System.Text.Encoding]::Default).GetBytes($jwtClaim)
$jwtClaimBase64 = [Convert]::ToBase64String($jwtClaimByte)
# BASE64をBASE64URLに変更
$jwtClaimBase64 = $jwtClaimBase64.Replace('+','-')
$jwtClaimBase64 = $jwtClaimBase64.Replace('/','_')
$jwtClaimBase64 = $jwtClaimBase64.Replace('=','')
# JWTの署名の作成準備
$signature=$jwtHeaderBase64+ '.' + $jwtClaimBase64
$signatureByte = ([System.Text.Encoding]::Default).GetBytes($signature)
# SHA256 オブジェクトの生成
$SHA256 = New-Object System.Security.Cryptography.SHA256CryptoServiceProvider
# SHA256 Hash 値を求める
$HashBytes = $SHA256.ComputeHash($signatureByte)
# SHA256 オブジェクトの破棄
$SHA256.Dispose()
# RSACryptoServiceProviderオブジェクト作成し秘密鍵を取り出す
$rsaPara = ($cert.PrivateKey).ExportParameters($true)
$RSA = New-Object System.Security.Cryptography.RSACryptoServiceProvider($cert.PrivateKey.KeySize)
$RSA.ImportParameters($rsaPara);
# RSAPKCS1SignatureFormatterオブジェクト作成
$Formatter = New-Object System.Security.Cryptography.RSAPKCS1SignatureFormatter($RSA)
# ハッシュアルゴリズムを指定
$Formatter.SetHashAlgorithm("SHA256")
# JWTの署名を作成
$jwtSignatureByte = $Formatter.CreateSignature($HashBytes)
$jwtSignatureString = [System.Convert]::ToBase64String($jwtSignatureByte)
# オブジェクト削除
$RSA.Dispose()
# BASE64をBASE64URLに変更
$jwtSignatureString = $jwtSignatureString.Replace('+','-')
$jwtSignatureString = $jwtSignatureString.Replace('/','_')
$jwtSignatureString = $jwtSignatureString.Replace('=','')
# アサーションの作成
$assert = $signature + "." + $jwtSignatureString
# 認証トークンの作成
$json = Invoke-WebRequest -Uri "https://oauth2.googleapis.com/token" `
-Method POST `
-Body @{
"grant_type" = "urn:ietf:params:oauth:grant-type:jwt-bearer"
"assertion" = $assert
} `
-ContentType "application/x-www-form-urlencoded" | ConvertFrom-Json
# Cloud Storageのファイルをダウンロード
$outfilePath = $script_folder_path + "\outfile.txt"
Invoke-WebRequest -Uri "https://storage.googleapis.com/storage/v1/b/upload_imai/o/somefile.txt?alt=media" `
-Method GET `
-Headers @{"Authorization" = "Bearer " + $json.access_token} `
-OutFile $outfilePath
上記のコードを見ただけでどう使えばいいかがわかるような方はこの後の注意事項は飛ばしていただいて問題ありません。
Powershellスクリプトの注意事項
上記のPowershellスクリプトのコードには注意事項が2つあり、それはコードの一部をマスクしている以下の部分になります。
- 秘密鍵の名前
- サービスアカウントの名前
- Cloud Storageからファイルをダウンロードするところ
秘密鍵の部分はコードの以下のところになります。
# 秘密鍵の準備
$privateKeyPath = $script_folder_path + "\gc_private_key.p12"
$password = ConvertTo-SecureString "Password" -AsPlainText -Force
この”\gc_private_key.p12″のところは実際にダウンロードした秘密鍵の名前に変更してください。あわせて、”Password”のところも秘密鍵のパスワードに変更するようにしてください。
サービスアカウントの部分はコードの以下のところになります。
# JWTのクレームセットを作成
$jwtClaim = "{""iss"":""sa@gcproject.iam.gserviceaccount.com"",""scope"":""https://www.googleapis.com/auth/cloud-platform"",""aud"":""https://oauth2.googleapis.com/token"",""exp"":$EXP,""iat"":$IAT}"
この”sa@gcproject.iam.gserviceaccount.com”のところは実際に作成されたサービスアカウントのメールアドレスに変更して下さい。
Cloud Storageからファイルをダウンロードするところはコードの以下のところになります。
# Cloud Storageのファイルをダウンロード
$outfilePath = $script_folder_path + "\outfile.txt"
Invoke-WebRequest -Uri "https://storage.googleapis.com/storage/v1/b/upload_imai/o/somefile.txt?alt=media" `
-Method GET `
-Headers @{"Authorization" = "Bearer " + $json.access_token} `
-OutFile $outfilePath
おそらく皆さんの環境で同様のことを行われるかはわかりませんが、今回の検証のためこのコードは追加されています。この部分が不要な場合は削除されるようにしてください。
以上でPowershellスクリプトの注意点は終了となります。
Powershellスクリプトの実行と確認
作成したPowershellスクリプトを実行する準備をします。今回は同じフォルダの中にスクリプトファイルと秘密鍵ファイルを配置します。スクリプトのファイル名はsa-token.ps1という名前で保存しています。
このsa-token.ps1ファイルを右クリックしていただき、Powershellで実行を押していただくとoutfile.txtというファイルがダウンロードされます。もし、ダウンロードできずエラーになってしまった場合は、前セクションの注意事項を再度確認してみてください。
余談
Powershellスクリプトを作成する前に本当はバッチで実施できないかと考えて作成していました。もっとニッチなものを作成したいと考えていたためです。ただ、バッチファイルでは秘密鍵によるRSA署名を実装するところが私のスキルでは難しく今回は断念してしまいました。いつかバッチファイルでも今回実施していることを実現したいと考えています。
おわりに
今回の記事では、Powershellの標準コマンドを使って、Google Cloudに接続する方法を紹介しました。この方法を使用することで、Google Cloud SDKをインストールする必要がなく、Powershellの標準コマンドとGoogle Cloud APIを使用することで、より柔軟な環境でGoogle Cloudに接続できるようになります。
この方法を使用することで、Google Cloud SDKのバージョン管理やアップグレードの問題を避けることができます。(gcloudコマンドを利用できた方が便利だとは思います。)また、今回のPowershellのスクリプトを使用して、自動化された処理を実行することができます。これによって、より迅速に反応し、より正確な操作を実行することができます。
最後に、この記事がどなたかのGoogle Cloud接続に役立つことを願っています。Powershellの標準コマンドとGoogle Cloud APIを使用することで、より柔軟で生産的な環境でGoogle Cloudに接続することができます。是非、この方法を活用して、より効率的な開発を実現してください。