1
/
5

AWSのTerraform標準化を今一度サマってみる

おはようございます。12/24、クリスマスイブ担当の中原と申します。
現在はSREチームとしてチームに従事しております。

クリスマス・イブ、みなさんはどのように過ごされるでしょうか。
平日真っ只中、年末の駆け込みなどで忙しいでしょうが良い年末を送れるように、
この記事がなにかの一助になれば幸いです。

ターゲットとしてはAWSでのTerraform初学者向けとなっております。

目次

  • はじめに

  • 引用元について

  • 概要

  • 解説

  • AssumeRoleについての補足(AssumeRoleとはという解説パート)

  • 最小特権の原則に従う

  • IAM ロールを使用する

  • ローカル認証用のIAMロールを引き受ける

  • 標準リポジトリ構造の実装

  • ルートモジュール構造

  • 再利用可能なモジュール構造

  • リソースの命名に関するガイドラインに従う

  • デフォルトのタグを使用する

  • コーディング標準に従う

  • スタイルガイドラインに従う

はじめに

本記事はAWSの環境においてのベストプラクティスをわかりやすくまとめた記事となります。
他パブリッククラウドや、個人の思想が介入したものではなく、AWSが出しているベストプラクティスをサマリした記事になります。

引用元について

以下、AWS公式の記事から引用しております。そちらを噛み砕いた記事になります。
https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/terraform-aws-provider-best-practices/terraform-aws-provider-best-practices.pdf

概要

Terraform AWS プロバイダーは、TerraformでAWS infrastructure as code (IaC) を管理するための公式プラグインです。Terraform 構文をAWS API コールに変換して、 AWS リソースを作成、読み取り、更新、削除 します。

例文
エイリアスで複数の AWS プロバイダーブロックを使用して、別のリージョンとアカウントにレプリカを持つ Amazon Relational Database Service (Amazon RDS) データベースを管理するTerraform 設定の例です。

# Configure the primary AWS Provider
provider "aws" {
region = "us-west-1"
alias = "primary"
}
# Configure a secondary AWS Provider for the replica Region and account
provider "aws" {
region = "us-east-1"
alias = "replica"
assume_role {
role_arn = "arn:aws:iam::<replica-account-id>:role/<role-name>"
session_name = "terraform-session"
}
}
# Primary Amazon RDS database
resource "aws_db_instance" "primary" {
provider = aws.primary
# ... RDS instance configuration
}
# Read replica in a different Region and account
resource "aws_db_instance" "read_replica" {
provider = aws.replica
# ... RDS read replica configuration
replicate_source_db = aws_db_instance.primary.id
}

解説

  • 最初のproviderブロックは、 us-west-1 リージョンのプライマリAWSプロバイダーをエイリアスで設定します。日本リージョンで使う場合はap-northeast-1に置き換えてください。
  • 2番目のproviderブロックは、 us-east-1 リージョンのセカンダリAWSプロバイダーをエイリアスで設定します(replicaの設定になります)このプロバイダーは、別のリージョンとアカウントにプライマリデータベースのリードレプリカを作成するために使用されます。assume_roleブロックは、レプリカアカウントの IAM ロールを引き受けるために使用されます。引き受ける IAM ロールの Amazon リソースネーム (ARN) role_arnを指定し、session_nameはTerraformセッションの一意の識別子です。
  • aws_db_instance.primaryリソースは、us-west-1リージョンのprimaryプロバイダーを使用してプライマリ Amazon RDS データベースを作成します。
  • aws_db_instance.read_replicaリソースは、 replicaプロバイダーを使用して、 us-east-1リージョンにプライマリデータベースのリードレプリカを作成します。replicate_source_db 属性はprimaryデータベースの ID を参照します。

ここで覚えていただきたいことは、role_arnでIAMロールの引き渡しを行っているという点です。
(AssumeRoleと言います)
AssumeRoleについてですが、IAMロールが別のロールを引き受けるには、引き受けられるロールの「信頼関係(trust relationship)」を編集する必要があります。
引き受ける側ではないことに注意してください。
またPassRoleとは異なるため留意してください。

AssumeRoleについての補足(AssumeRoleとはという解説パート)

IAM ロールが別のロールを引き受けることを許可するには、引き受けるロールの信頼関係を変更する必要があります。このプロセスは、ロールが同じアカウント内に存在するか、別のアカウントにあるかによって異なります。

同じアカウント内のロール(RoleA)

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:role/Role_A"
},
"Action": "sts:AssumeRole"
}
]
}

同じアカウント内でロールが別のロールを引き受けることを可能にするために必要なのは、これだけです。

異なるアカウント
Role_Bの信頼関係を変更して、 Role_Aがそれを引き受けられるようにする必要があります。ここでの違いは、 には権限Role_Aを含むsts:AssumeRoleの追加ポリシーが必要になることです。したがって、最終結果は次のようになります。

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:role/Role_A"
},
"Action": "sts:AssumeRole"
}
]
}

また、Role_Aポリシーとして以下を添付する必要があります。

{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::222222222222:role/Role_B"
}
}

最小特権の原則に従う

ユーザー、プロセス、またはシステムが意図した機能を実行するために必要な最小限 のアクセス許可のみを付与することを指す基本的なセキュリティ原則です。これは、アクセスコント ロールの中核となる概念であり、不正アクセスや潜在的なデータ侵害に対する予防手段です。
Terraform を使用してAWS リソースをプロビジョニングおよび管理する場合、API呼び出しを実行するための適切なアクセス許可を必要とするエンティティ (ユーザーまたはロール) に代わって機能します。最小特権に従わないと、主要なセキュリティリスクが生じます。

つまり必要な権限を必要な人にだけ適切に割り当てようという思想です。

IAM ロールを使用する

Terraform AWS プロバイダーでセキュリティを強化するために、可能な限りIAMユーザーIAMの代わりにロールを使用します。IAM ロールは、自動的にローテーションする一時的なセキュリティ認証情報を提供するため、長期的なアクセスキーを管理する必要がなくなります。ロールは、IAMポリシーを通じて正確なアクセスコントロールも提供します。

ユーザーではなくIAMロールを作成すれば自動でローテーションされます。

ローカル認証用のIAMロールを引き受ける

Terraform をローカルで実行するときは、静的アクセスキーを設定しないでください。代わりに、 ロールを使用してIAM、長期的な認証情報を公開せずに特権アクセスを一時的に付与します。 まず、必要な最小限のアクセス許可を持つIAMロールを作成し、ユーザーアカウントまたはフェデレーションIDがIAMロールを引き受けることを可能にする信頼関係を追加します。これにより、 ロールの一時的な使用が許可されます。

アクセスキーの発行は便利でもありますが、セキュリティに問題がありますのでロールを使用します。
AWSのアクセスキーのセキュリティについては以下ポリシーを参照ください。
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/best-practices.html

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111122223333:role/terraform-execution"
 },
"Action": "sts:AssumeRole"
}
]
}

次に、 AWS CLIコマンド aws sts assume-role を実行して、ロールの有効期間の短い認証情報を取得します。これらの認証情報は通常 1 時間有効です。

aws sts assume-role --role-arn arn:aws:iam::111122223333:role/terraform-execution --
role-session-name terraform-session-example

コマンドの出力には、AWSへの認証に使用できるアクセスキー、シークレットキー、およびセッショントークンが含まれています。

{
"AssumedRoleUser": {
"AssumedRoleId": "AROA3XFRBF535PLBIFPI4:terraform-session-example",
"Arn": "arn:aws:sts::111122223333:assumed-role/terraform-execution/terraformsession-example"
},
"Credentials": {
"SecretAccessKey": " wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"SessionToken": " AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT
+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/
IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/
AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE",
"Expiration": "2024-03-15T00:05:07Z",
"AccessKeyId": "ASIAIOSFODNN7EXAMPLE"
}
}

IAM ロールを引き受けるプロバイダー設定の例:

provider "aws" {
assume_role {
role_arn = "arn:aws:iam::111122223333:role/terraform-execution"
session_name = "terraform-session-example"
}
}

これにより、Terraformセッションの期間だけ昇格された権限が付与されます。テンポラリーキーは、セッションの最大期間後に自動的に期限切れになるため、リークできません。

その他にも多数機能がありますが、今回はTerraformをAWSで作成するベストプラクティスになるため割愛します。興味がある方は原文を参照して戴ければと思います。そのためIAMの一部権限のみを抜粋して記載しました。

標準リポジトリ構造の実装

  • ルートモジュールまたはディレクトリ
  • README
  • main.tf
  • variables.tf
  • locals.tf
  • versions.tf
  • data.tf
  • .tfvars
  • サービス名付きファイル
  • カスタムスクリプト
  • 静的ファイル
    などを格納します。

ルートモジュール構造

Terraform ルートモジュールレイアウトの基本例

.
### data.tf
### envs
# ### dev
# # ### terraform.tfvars
# ### prod
# # ### terraform.tfvars
# ### test
# ### terraform.tfvars
### locals.tf
### main.tf
### outputs.tf
### providers.tf
### README.md
### terraform.tfvars
### variables.tf
### versions.tf

再利用可能なモジュール構造

Terraformは、ローカル相対パスまたはリモートリポジトリからモジュールをロードできます。モジュールが多くの設定で再利用されることが予想される場合は、独自のバージョン管理リポジトリに配置します。

.
### data.tf
### examples
# ### multi-az-new-vpc
# # ### data.tf
# # ### locals.tf
# # ### main.tf
# # ### outputs.tf
# # ### providers.tf
# # ### README.md
# # ### terraform.tfvars
# # ### variables.tf
# # ### versions.tf
# # ### vpc.tf
# ### single-az-existing-vpc
# # ### data.tf
# # ### locals.tf
# # ### main.tf
# # ### outputs.tf
# # ### providers.tf
# # ### README.md
# # ### terraform.tfvars
# # ### variables.tf
# # ### versions.tf
### iam.tf
### locals.tf
### main.tf
### outputs.tf
### README.md
### variables.tf
### versions.tf

上記が公式リファレンスによる推奨のコード記載になります。
どれも重要なのですがここではあえて抜粋して必要な点を記載します。


リソースの命名に関するガイドラインに従う

  • Terraform スタイルの標準に一致するように、すべてのリソース名に snake_case (小文字はアン ダースコアで区切られます) を使用します。この方法により、リソースタイプ、データソースタイ プ、およびその他の事前定義された値の命名規則との一貫性が保証されます。この規則は名前引数 には適用されません。
  • そのタイプの唯一のリソース (モジュール全体の単一のロードバランサーなど) への参照を簡素化 するために、リソースに mainまたはthisという名前を付けます。
  • リソースの目的とコンテキストを記述し、同様のリソース (例えば、メインデータベースprimaryの場合とデータベースのリードレプリカread_replicaの場合) を区別するのに役立つわかりやすい名前を使用します。
  • 複数名ではなく単一の名前を使用します。
  • リソース名でリソースタイプを繰り返しないでください。

デフォルトのタグを使用する

タグを受け入れることができるすべてのリソースにタグを割り当てます。
Terraform AWS プロバイダーには、ルートモジュール内で使用する必要がある
aws_default_tags データソースがあります。
Terraform モジュールによって作成されたすべてのリソースに必要なタグを追加することを検討してください。アタッチできるタグのリストを次に示します。

  • 名前: 人が読めるリソース名
  • AppId: リソースを使用するアプリケーションの ID
  • AppRole: リソースの技術機能。例えば、「webserver」や「database」など。
  • AppPurpose: リソースのビジネス目的。例えば、「フロントエンド ui」や「支払いプロセッサ」 など。
  • 環境 : 開発、テスト、製品などのソフトウェア環境
  • プロジェクト : リソースを使用するプロジェクト
  • CostCenter: リソース使用量の請求先

できれば決定した命名に従うのがよろしいかと思われます。

コーディング標準に従う

一貫した Terraform フォーマットルールとスタイルをすべての設定ファイルに適用します。CI/CD パ イプラインで自動スタイルチェックを使用して標準を適用します。コーディングのベストプラクティ スをチームワークフローに埋め込むと、組織全体で使用量が広く普及するにつれて、設定は読み取りやすく、保守しやすく、共同作業性が保たれます。

スタイルガイドラインに従う

  • すべての Terraform ファイル (.tf ファイル) を terraform fmt コマンドで HashiCorp スタイル標準 に合わせてフォーマットします。
  • terraform validate コマンドを使用して、設定の構文と構造を確認します。
  • TFLintを使用してコード品質を静的に分析します。この linter は、フォーマットだけでな く、Terraform のベストプラクティスをチェックし、エラーが発生したときにビルドに失敗します。

これらを念頭に置いて作業することによりより良いコードが担保できるかと思います。
他にも色々ありますが一旦こちらを参照いただき、きれいなコードが書けるようになりましょう!

Terraformについてよりよく学びたい方は以下の本を参考にすると良いと思います。

詳解Terraform 第三版 https://www.amazon.co.jp/dp/4814400527/
入門Terraform クラウド時代のインフラ統合管理 https://www.amazon.co.jp/dp/429502063X/

以上です。
明日は鎌田さんの記事になりAdvent Calendar最終日となります!!!

このストーリーが気になったら、遊びに来てみませんか?
インフラエンジニア、PHPエンジニアさん募集中!
株式会社スタジオ・アルカナでは一緒に働く仲間を募集しています
2 いいね!
2 いいね!

同じタグの記事

今週のランキング

中原 一也さんにいいねを伝えよう
中原 一也さんや会社があなたに興味を持つかも