Organization単位でSavings Plansを購入するために、アカウントごとに共有された金額を集計してみた

## はじめに
自社内でSavings PlansをOrganization(組織)単位で購入した時に必要になった処理について共有しようと思います。

Savings Plans自体についての詳細な説明はここでは割愛させて頂きますが、Savings Plansには所属Organizationの他アカウントと割引を共有する機能があります。
その共有を活用した際に課題があり、それを解決するのが今回の処理です。


## 処理を作成した背景
自社内では各部署がAWSアカウントを作成し使用していますが、基本的に同じOrganizationに所属しています。
全アカウントでSavings Plansを有効に活用できているというわけではなかったため、コスト削減を目的に組織単位でSavings Plansを買いたい状況でした。
Savings Plansの購入自体はとても簡単で、購入額や期間、前払いするかどうかを決めれば後は購入するだけなのですが、自社では上記のようなOrganizationの状況なので、別の課題がありました。


## 課題
それは、Savings Plans購入費用をどこが持つのかという課題です。
Savings Plansを購入すると割引が受けられますが、
各部署で使用されたEC2やLambdaの使用量のうち、割引された額をSavings Plansを購入したアカウントが支払う形になります。

言ってしまえば購入したアカウントを保有する部署が、他の部署が使用した料金を肩代わりするようなものです。
そのような状況では購入することができませんでした。


## 解決策
どのアカウントにいくらSavings Plansが割り振られたかを確認することが解決策になりました。
部署間のコストの振替は可能ですので、後は具体的な金額を算出できれば、各部署はSavings Plansの割引適用後の使用した分だけ支払うことが可能でした。


## 具体的な解決方法
前置きが長くなりましたが、どのように解決したかの共有です。
Savings Plansがどのアカウントにいくら割り振られたかを確認するには、
AWS Cost and Usage Reports(CUR)と、共有のため購入したSavings Plan IDが必要です。
購入したSavings Plan IDは、[インベントリ](https://docs.aws.amazon.com/ja_jp/savingsplans/latest/userguide/ce-sp-inventory.html)から確認できます。

### CUR設定
CURを作成します。
[コストと使用状況レポートを作成する](https://docs.aws.amazon.com/ja_jp/cur/latest/userguide/cur-create.html)
今回の用途であれば、
Time granularityは1か月、Report versioningは上書きで問題ありません。
後程Athenaを使用しクエリするので、圧縮タイプはParquetを選択してください。


### Athena設定
CURを扱うテーブルを作成します。
手動で構築することも可能ですが、CURを出力するように設定したバケットにはAthena設定用のテンプレートが格納されています。
それを使用することがAWS公式でも推奨されています。
[AWS CloudFormation テンプレートを使用した Athena のセットアップ](https://docs.aws.amazon.com/ja_jp/cur/latest/userguide/use-athena-cf.html)


## 各アカウントのSavings Plans金額確認
作成したテーブルに対してクエリを実行します。
なお、例えば2023年12月のコスト取得例が以下になりますが、
実行日時について注意点があります。
CURは完全に集計が完了するまで数日かかります。
実行日時が2024年1月1日では集計が完了していない可能性がありますので、
月初から10日程経ってからの実行をお勧めします。

```sql
SELECT line_item_usage_account_id AS "Account Id",
       line_item_legal_entity AS "Legal Entity",
       SUM(savings_plan_net_savings_plan_effective_cost) AS "Amount (USD)",
       savings_plan_savings_plan_a_r_n AS "Savings Plans Id"
FROM (データベース名).(テーブル名)
WHERE year='2023'
  AND month='12'
  AND line_item_line_item_type = 'SavingsPlanCoveredUsage'
  AND savings_plan_savings_plan_a_r_n = 'arn:aws:savingsplans::(SP購入AWSアカウントID):savingsplan/(Savings Plan ID)' 
GROUP BY line_item_usage_account_id,
         line_item_legal_entity,
         savings_plan_savings_plan_a_r_n
```

### 複数Savings Plan IDがある場合
利用料金が下がる可能性もあるため、一度に多くの金額をコミットするのはリスクがあります。
そのため何度かに分けてSavings Plansを購入することもあるかと思いますので、以下にその場合のクエリを記載します。
複数のSavings Plan IDが対象に含まれれば良いため、

    savings_plan_savings_plan_a_r_n = 'arn:aws:savingsplans::(SP購入AWSアカウントID):savingsplan/(Savings Plan ID)' 

の部分を、

    savings_plan_savings_plan_a_r_n LIKE 'arn:aws:savingsplans::(SP購入AWSアカウントID):savingsplan/%'

のように変更すれば問題ありません。

### クエリ結果
上記により、以下のようなレコードが取得できます。
| Account Id | Legal Entity | Amount (USD) | Savings Plans Id |
|:-----------:|:------------:|:------------:|:------------:|
| 111111111111 | Amazon Web Services Japan G.K. | 5118.590701425601 | arn:aws:savingsplans::(SP購入AWSアカウントID):savingsplan/(Savings Plan ID) |
| 222222222222 | Amazon Web Services Japan G.K. | 187.7021327 | arn:aws:savingsplans::(SP購入AWSアカウントID):savingsplan/(Savings Plan ID) |
| 333333333333 | Amazon Web Services Japan G.K. | 2585.2460987617997 | arn:aws:savingsplans::(SP購入AWSアカウントID):savingsplan/(Savings Plan ID) |
| 444444444444 | Amazon Web Services Japan G.K. | 12.171609 | arn:aws:savingsplans::(SP購入AWSアカウントID):savingsplan/(Savings Plan ID) |
| 555555555555 | Amazon Web Services Japan G.K. | 5.379112028 | arn:aws:savingsplans::(SP購入AWSアカウントID):savingsplan/(Savings Plan ID) |

これで各AWSアカウントにいくら分割り振られたかがわかります。
Savings Plans購入アカウントでもEC2等使用している場合は、この出力結果にそのアカウントのSavings Plans使用量が出力されます。
ですので、Savings Plans合計金額を購入アカウントから引き、それぞれのアカウントに使用量を加算することで各アカウント使用量が算出でき、コストの振替が可能です。

### * (コスト管理に慣れている方ならお分かりかと思いますが、これで終わりではありません)


## 落とし穴
Savings Plans の購入費用に対する税金を計算しなければいけません。(1敗)
Savings Plans購入アカウントに税金を負担させてしまうことになります。

当然AWSの利用料金にも10%の税金(2024/1/30現在)がかかりますので、使用したSavings Plans利用料金の1.1倍を各アカウントのAWS利用料金には加算すべきです。

そして前述したSavings Plans合計金額は、AWS利用料金としてはその1.1倍が請求されます。
Savings Plans購入アカウントからはその金額をAWS使用料金からは引くべきです。

上記計算を含めて初めてSavings Plansのアカウント共有を達成することが出来ました。

以上になります。
参考になれば幸いです。