ゴール
自動でAWSの月額コストを取得して、Google スプレッドーシートに書き込むということをやる
やってみた結果
Slackで取得してもよかったが、過去のコスト情報として残しておきたかったのでGoogleスプレッドシートを使用した。
認証部分は先人のライブラリを使うことでシュッとできたが、APIの引数の取得が大変だった。
手順
1. Googleスプレッドシートを用意します
手順は割愛
2. Apps Scriptの画面を開く
手順は割愛
3. aws.gsファイルを作成し、コードを貼り付ける
aws.gsファイルを作成します。
aws.jsファイルの中身をコピーします。
aws.gsファイルに貼り付けます。
4. テスト関数を設定する
まずはテスト関数を作成し、AWSの認証と情報取得ができることを確認します。
ここが上手く行かないと、AWS Cost Explorerの細かいパラメータ作成ができません。
main.gsファイルを作成し、下記(テスト関数)をコピー&ペーストします。
main.gs
function test(){
const awsAccessKey = PropertiesService.getScriptProperties().getProperty("AWS_ACCESS_KEY");
const awsSecretKey = PropertiesService.getScriptProperties().getProperty("AWS_SECRET_KEY");
AWS.init(awsAccessKey, awsSecretKey)
const res = AWS.request(
'ce',
'us-east-1',
'AWSInsightsIndexService.GetCostAndUsage',
{},
'POST',
{"TimePeriod": {"Start": "2023-06-01", "End": "2023-07-01"}, "Granularity": "MONTHLY", "Metrics": ["BlendedCost"]},
{"Content-Type": "application/x-amz-json-1.1"},
)
const code = res.getResponseCode()
const text = res.getContentText();
Logger.log(code)
Logger.log(text)
}
5. スクリプトプロパティを設定します
スクリプトプロパティを設定します。
プロパティ | 値 |
---|---|
AWS_ACCESS_KEY | AWSのIAMから取得したものを設定 |
AWS_SECRET_KEY | AWSのIAMから取得したものを設定 |
6. テスト実行
テスト関数を実行します
実行したあと、下記のようなログが出力されれば正常に情報が取得されています。
そして Amount
に金額は入っています。
ここまででAWSの認証とAWS Cost Explorerから情報を取得できました。
7. Cost Explorerのパラメータを作成する
今度はAWS Cost Explorerのパラメータを作成します。
先ほどのテスト関数は先月分の全体の金額を取得するものでした。
今回は特定のタグがついたリソースの金額を取得することを目標とします。
このパラメータ作成はこちらの記事がとても参考になります。
この記事で紹介されているパラメータの確認の方法はAWS CLIのログから確認するという方法です。まずはAWS CLIで特定のタグが付いたリソースの金額を取得してみます。
TAG-VALUEには実際のタグの値を入れてください
aws ce get-cost-and-usage --time-period Start="2023-06-01",End="2023-07-01" --granularity MONTHLY --metrics "BlendedCost" "UnblendedCost" --group-by Type=TAG,Key=Customer --filter '{"Tags": { "Key": "Customer", "Values": ["TAG-VALUE"] }}' --debug
ログの一部
2023-07-11 14:44:31,108 - MainThread - botocore.endpoint - DEBUG - Making request for OperationModel(name=GetCostAndUsage) with params: {'url_path': '/', 'query_string': '', 'method': 'POST', 'headers': {'X-Amz-Target': 'query_string', 'Content-Type': 'application/x-amz-json-1.1', 'User-Agent': 'aws-cli/2.9.21 Python/3.9.11 Darwin/21.6.0 exe/x86_64 prompt/off command/ce.get-cost-and-usage'}, 'body': b'{"TimePeriod": {"Start": "2023-06-01", "End": "2023-07-01"}, "Granularity": "MONTHLY", "Metrics": ["BlendedCost", "UnblendedCost"], "GroupBy": [{"Type": "TAG", "Key": "Customer"}]}', 'url': 'https://ce.us-east-1.amazonaws.com/', 'context': {'client_region': 'aws-global', 'client_config': <botocore.config.Config object at 0x7fab5825a730>, 'has_streaming_input': False, 'auth_type': 'v4', 'signing': {'region': 'us-east-1', 'signing_name': 'ce'}}}
パラメータ一覧
引数番号 | 実際の値 | 引数の値の特定方法 |
---|---|---|
1. サービス | ce |
ログ中の url のサブドメインを参照
|
2. リージョン | us-east-1 |
ログ中の url のサブドメインを参照
|
3. アクション | AWSInsightsIndexService.GetCostAndUsage |
ログ中の headers の X-Amz-Target を参照
|
4. パラメータ | {} |
ログ中の query_string を参照 (多分)
|
5. メソッド | POST |
ログ中の method を参照
|
6. ペイロード | {"TimePeriod": {"Start": 2023-06-01, "End": 2023-07-01}, "Granularity": "MONTHLY", "Filter": {"Tags": {"Key": "Customer", "Values": ["TAG-VALUE"]}}, "Metrics": ["BlendedCost", "UnblendedCost"], "GroupBy": [{"Type": "TAG", "Key": "Customer"}]} |
ログ中の body を参照TAG-VALUEには実際のタグの値を入れてください |
7. ヘッダ | {"Content-Type": "application/x-amz-json-1.1"} |
ログ中の headers の Content-Type を参照
|
8. パス | / |
ログ中の url_path を参照 (多分)
|
※この表は このサイト を参考に作成しております。
パラメータが確認できたので、あとはこれをGASで使えるように形式を整えます。
整えたら、テスト関数の該当箇所と入れ替えます。
最終的なコード
function test(){
const awsAccessKey = PropertiesService.getScriptProperties().getProperty("AWS_ACCESS_KEY");
const awsSecretKey = PropertiesService.getScriptProperties().getProperty("AWS_SECRET_KEY");
AWS.init(awsAccessKey, awsSecretKey)
const res = AWS.request(
'ce',
'us-east-1',
'AWSInsightsIndexService.GetCostAndUsage',
{},
'POST',
{"TimePeriod": {"Start": costStart, "End": costEnd}, "Granularity": "MONTHLY", "Filter": {"Tags": {"Key": "Customer", "Values": ["TAG-VALUE"]}}, "Metrics": ["BlendedCost", "UnblendedCost"], "GroupBy": [{"Type": "TAG", "Key": "Customer"}]},
{"Content-Type": "application/x-amz-json-1.1"},
'/'
)
const code = res.getResponseCode()
const text = res.getContentText();
Logger.log(code)
Logger.log(text)
}
これで特定のタグが付いたリソースの先月分の金額が取得できました。
8. 取得したデータの取り出し
今度は取得したデータを取り出せるようにしていきます。
参考にしたサイトではXMLで取得されると書かれていましたが、私の環境ではJSONで取得
されました。私はここで30分ハマったので気をつけてください。
// resにレスポンスデータが入っている
const code = res.getResponseCode();
const text = res.getContentText();
// JSON
const data = JSON.parse(text);
// BlendedCostの値を取得する
monthCost = Math.floor(data.ResultsByTime[0].Groups[0].Metrics.BlendedCost.Amount * 100) / 100;
Logger.log(monthCost)
return monthCost
これで金額を取り出すことができました。
9. スプレッドシートへの書き込み
あとはスプレッドシートへ書き込みするだけです。
これは他にもたくさん情報がでているのでそちらを見てください
ハマったところ
一番ハマったのが、他の記事ではXMLで取得されていると紹介されていましたが、実際はJSONで取得されているところでした。
ここに行き着くまでにわりと時間がかかりました。
const data = JSON.parse(text);
最後に
コスト情報は経理なども確認したい内容だと思うので、GASでコストデータを取得するというのはわりとありな気がしています。
実際はAWSマネジメントコンソールの権限を経理に付与するか、このような形でGoogleスプレッドシートで過去の金額含めて確認できるようにするか、Slack Botでピンポイントの値が確認できるようにするか、といくか方法が考えられます。
人や状況に合わせて最適なものを選択していきましょう。