AWS費用監視ツール(前編:AWS マネジメントコンソール&AWS CLI)

# 1. はじめに
こんにちは、(株)日立製作所、クラウドビジネス推進センタの富田です。

「AWS費用のデイリー通知、やってますか？」

AWSにある程度精通しているエンジニアであれば「Lambdaでササっと作ってしまう」という芸当も難しくはないのですが、普段AWS マネジメントコンソール(以後「マネコン」と略す)をメインで使っている場合、Lambdaでの実装にはハードルを感じるという方もおられると思います。

- 「毎日マネコンにログインして、Cost Explorerで費用をチェックするのも面倒」
- 「通知ツール作るのって大変なのだろうか？難しくなければ自分で試してはみたいが。。。」

本記事では、AWS費用の監視・通知ツールをテーマに、ステップ・バイ・ステップで解説したいと思います。

# 2. 全体構成
記事は2部構成になっています。

- AWS費用監視ツール(前編:AWS マネジメントコンソール&AWS CLI) **← 本記事**
- AWS費用監視ツール(後編:Lambda活用)

<div align="center">
  <a href="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img1.png?raw=true">
    <img alt="img1" src="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img1.png?raw=true">
  </a>
</div>

前編では、ヒューマンインタフェースであるマネコンとCLIを使います。CLIが使えれば、タスクマネージャーやcronなどによる自動化も可能です。後編では、コーディングが必要となるため難易度は上がります。しかし、自身で開発しなくても、なんとなくやっている事が理解できれば、(新人や若手?)メンバにお願いもしやすくなるかもしれません
それでは、さっそく始めていきましょう！

# 3. AWS マネジメントコンソールでの確認
マネコンのCost Exploreで費用を確認してみます。期間とフィルターを指定すると、結果がグラフやテーブルといったビューで確認できます。ビューでは、グラフの種類や、サービス毎、連結アカウント毎など、どういう視点で情報をみたいかの指定も可能です。

<div align="center">
  <a href="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img2.png?raw=true">
    <img alt="img2" src="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img2.png?raw=true">
  </a>
</div>

フィルター条件を使うと、例えばアカウントにクーポンなどクレジットが適用されている場合など、クレジット適用前、適用後の費用確認も可能になります。デフォルト(フィルター条件なし)では、クレジット適用済みの料金が表示されます。

<div align="center">
  <a href="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img3.png?raw=true">
    <img alt="img3" src="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img3.png?raw=true">
  </a>
</div>

逆に、クレジット適用前の費用は、「料金タイプ」で「使用料」と「税金」を除く事で表示(確認)します。

<div align="center">
  <a href="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img4.png?raw=true">
    <img alt="img4" src="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img4.png?raw=true">
  </a>
</div>

蛇足になりますが、以前、私が管理するアカウントに対しクレジット適用済みの料金通知だけしてました。すると**毎日「0.00USD」の通知**だけになってしまい「ちょっとなぁ」という感じでした。各サービスがどの程度使われているのかの目安も知りたかったので、クレジット適用前後の通知をするようになりました。
次に、このGUIを踏まえ、(クレジット適用前後のAWS費用について)CLIを使って監視してみます。

# 4. AWS CLIでの確認
AWS CLIは、マネコンに代わるユーザインタフェースです。AWS CLI自体は、ユーザ端末にあるため、マネコンのように「ユーザ名・パスワード(場合によってはMFA)」による認証はありません。代わりに「アクセスキー」と「シークレットキー」を使います。例えば、次のようなドキュメントを参考に、AWS CLIのインストール&セットアップを行ってください。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html

「アクセスキー」と「シークレットキー」の準備ができたらプロファイルを設定します。通常このプロファイルを記載する構成ファイルは、ユーザ端末のカレントディレクトリ(ホームディレクトリ)にある「.aws」ディレクトリにあります。プロファイルの設定が終わったら、試しにコマンドを実行し、自分が接続しようとしているAWSアカウントに接続できているか確認してみましょう。スマートな確認方法ではありませんが、私は次のようなバケット一覧を取得するコマンドを実行し、接続しようとしているアカウント内のS3バケット一覧と一致しているか見比べています。

:::note warn
「アクセスキー」と「シークレットキー」のペアが他人に漏れると、このIAMユーザの権限でリモートからAWSリソースの操作が可能になります。漏洩しないように厳重に管理しましょう！
:::

```
% aws --profile=billing-user s3 ls
(バケット一覧)
```

コマンドの引数「--profile」として、プロファイル名を指定していますが、毎回記載するのが面倒であれば、シェルの環境変数に設定しておく方法もあります。

```
#シェルの環境変数に設定
% export AWS_PROFILE=billing-user

#引数「--profile」の指定が不要
% aws s3 ls
(バケット一覧)
```

それでは、3章のマネコン(GUI)経由で取得した期間のデータを、AWS CLIで取得してみます。初めに、期間をシェル変数へ設定します。

```
% START=2021-11-01
% END=2021-12-01   #下記マニュアルより、最終日は除かれるため1日増やす
```

使うコマンドは下記「aws ce get-cost-and-usage」になります。

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ce/get-cost-and-usage.html

マニュアル通り実行してみます。JSON形式で期間のAWS費用合計が得られました。

```
% aws --profile=billing-user ce get-cost-and-usage \
--time-period Start=${START},End=${END} \
--granularity MONTHLY \
--metrics "AmortizedCost"
{
    "ResultsByTime": [
        {
            "TimePeriod": {
                "Start": "2021-11-01",
                "End": "2021-12-01"
            },
            "Total": {
                "AmortizedCost": {
                    "Amount": "209.1272342834",
                    "Unit": "USD"
                }
            },
            "Groups": [],
            "Estimated": false
        }
    ],
    "DimensionValueAttributes": []
}
```

この中で、「209.1272342834」の部分を抜き出してみます。次のように「--query」と「--output」で調整できます。如何でしょう？難しくないですね！

```
% aws --profile=billing-user ce get-cost-and-usage \
--time-period Start=${START},End=${END} \
--granularity MONTHLY \
--metrics "AmortizedCost" \
--query "ResultsByTime[].Total[].AmortizedCost.Amount" \
--output text
209.1272342834
```

では、クレジット適用前の使用料を取得してみます。フィルターで「料金タイプ」から「クレジット」を抜けばよかったので、「--filter」オプションで調整します。filter.jsonという名前のJSONファイルを準備します。

```json:filter.json
{
    "Not": {
        "Dimensions": {
            "Key": "RECORD_TYPE",
            "Values": [
                "Credit"
            ]
        }
    }
}
```

再度実行してみます。無事クレジット適用前のAWS料金が得られましたね。

```
% aws --profile=billing-user ce get-cost-and-usage \
--time-period Start=${START},End=${END} \
--granularity MONTHLY \
--metrics "AmortizedCost" \
--filter file://filter.json \
--query "ResultsByTime[].Total[].AmortizedCost.Amount" \
--output text
440.2072342834
```

前編はここまでになります。お疲れ様でした。**(後編へ続く)**

---
* Amazon Web Services、および、その他のAWS 商標は、米国およびその他の諸国におけるAmazon.com, Inc.またはその関連会社の商標です。
* Microsoft 365、Microsoft Teamsは、米国Microsoft Corporationおよびその関連会社の米国およびその他の国における登録商標または商標です。
* その他、本資料に記述してある会社名、製品名は、各社の登録商品または商標です。

# 付録: REST APIへの接続確認
本編で使ったAWS CLIのコマンド「aws ce get-cost-and-usage」ですが、本当にREST APIを使っているのでしょうか？少し見てみましょう。

下記をみると、このコマンドが利用するREST APIのエンドポイントが確認できます。

> The Cost Explorer API provides the following endpoint:
> https://ce.us-east-1.amazonaws.com

https://docs.aws.amazon.com/cli/latest/reference/ce/index.html

```
% nslookup ce.us-east-1.amazonaws.com
Server:		240d:1a:344:8a00:e67e:66ff:fe10:c00f
Address:	240d:1a:344:8a00:e67e:66ff:fe10:c00f#53

Non-authoritative answer:
Name:	ce.us-east-1.amazonaws.com
Address: 34.224.108.137
Name:	ce.us-east-1.amazonaws.com
Address: 44.193.185.174
Name:	ce.us-east-1.amazonaws.com
Address: 3.225.236.210
```

何度かAWS CLIのget-cost-and-usageを実行して、パケットをキャプチャしてみます。確かに、AWS CLIからREST APIのエンドポイントにアクセスしていますね！

<div align="center">
  <a href="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img6.png?raw=true">
    <img alt="img6" src="https://github.com/t-tkm/aws-billing-tool-post/blob/imgs/imgs/img6.png?raw=true">
  </a>
</div>