はじめに
先日業務でAWSに触れる機会があり、初めてIAMについて学びました。
その経験をもとに、実際のコード例を交えながら解説していきます。
IAMとは?
AWSの各リソースに対するアクセス権限を管理し、セキュリティを向上させるためのサービスです。
全てのサービスへのアクセスは禁止されているデフォルトの状態から、「どのリソースに対して、誰が何を行うことができるのか(できないのか)」 を定めていくことで、システムやデータの安全性が保たれます。
IAMポリシー
「どのリソースに対して、誰が何を行うことができるのか(できないのか)」のうち、「誰が」以外を定めたものです。
IAMポリシーは原則として、単体ではアクセスの主体者を規定しておらず、後述のIAMユーザー・IAMロールと呼ばれる主体者にアタッチ(関連付け)することで機能します。
詳細な定義方法は後述します。
IAMユーザー
「誰が」を規定するものです。
主体者は運用者・開発者であって、SNSのアカウントのように一人につき一つ作成し、恒常的な権限が付与されます。
理解には、ルートユーザーとの対比が分かりやすいです。
AWSアカウントを契約したときに作成されるルートユーザーは、アカウント内の全リソースに対するフルアクセス権限が付与されており、誤操作やアカウント乗っ取りの際のリスクが高いです。
それに対し、IAMユーザーはIAMポリシーによって必要な権限のみを付与でき、リスクを最小限に抑えられることから、ルートユーザーではなくこちらの使用が推奨されています。
IAMグループ
IAMユーザーをグループ分けする機能です。
特定のIAMポリシーをグループ内の全ユーザーに一括して適用できるため、アクセス権限の管理が効率的に行えるようになります。
IAMロール
「誰が」を規定する2つ目の方法です。
主体者は限られておらず、また、恒常的ではなく一時的な権限が付与されます。
主にAWSリソースが、他のリソースにアクセスする際に使用します。
例えば、Lambda関数がAmazon S3バケット内のファイルを取得する必要がある場合、Lambdaに「S3バケットのファイルにアクセスする権限」を持つIAMロールを割り当てます。
実体験で学んだIAM
ここからは、主にIAMユーザーとIAMロールの違いを、実際の使用例に当てはめて解説します。
背景
私が行ったのは、Nuxt アプリから、CloudWatch Logsにログを書き込む処理を追加することでした。
アプリ内でconsoleメソッドを使用することで、Lambda単体でも自動的にログを出力しますが、そこにはLambda自体のログを含みます。コスト面からそれを排し、必要なログのみを AWS SDK で出力する必要がありました。
手順・IAMの使い分け
- Lambdaが自動でログ出力する、ロググループへのアクセス権限を拒否
- AWS SDKでのログ出力先の、ロググループ・ログストリームを作成
- AWS SDKでのログ出力関数を作成
- ログ出力関数を実行するLambdaの IAMロール を作成し、IAMポリシー をアタッチ
4のようにサービス(Lambda)が他のサービス(CloudWatch Logs)にアクセスする場合はIAMロールを使用し、その設定や1, 2のような、開発者によるサービスの操作には、IAMユーザーを使用します。
コード例
①Lambdaが自動でログ出力する、ロググループへのアクセス権限を拒否する
Lambdaはデフォルトでは、最初の呼び出し時に自動で作成するロググループに対し、consoleメソッドの内容を出力します。
このとき同時に出力される、consoleメソッドとは無関係なLambda自体のログ(↓)が今回不要なため、デフォルトのロググループへのログ出力権限を拒否します。
INIT_START Runtime Version: nodejs:22.v35
Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:8ce0861cbacc1c3e68742d7537616587fd39490817ec413514cf66613b6bed7d
下記が、権限を拒否するIAMポリシーです。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:<account_id>:*"
},
{
"Effect": "Deny",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:ap-northeast-1:<account_id>:log-group:/aws/lambda/<function_name>:*"
]
}
]
}
②ログ出力関数の書き込み先の、ロググループ・ログストリームを作成する
続いて、AWS SDKのログ出力先を作成します。
今回は出力自体に焦点を当てているため詳細な方法は省略します。
③AWS SDKでCloudWatchにログ出力する関数を作成
続いて、AWS SDKでログ出力関数を作成します。
PutLogEventsCommand
のコンストラクタに、ロググループ名・ログストリーム名・ログイベント(出力内容)を渡しています。
const {
CloudWatchLogsClient,
PutLogEventsCommand,
} = require('@aws-sdk/client-cloudwatch-logs');
const client = new CloudWatchLogsClient({
region: "ap-northeast-1",
});
exports.handler = (log) => {
const input = {
logGroupName: "/aws/lambda/<log_group_name>",
logStreamName: "<log_stream_name>",
logEvents: [
{
timestamp: Date.now(),
message: JSON.stringify(log),
},
],
};
client.send(new PutLogEventsCommand(input));
};
④ログ出力関数を実行するLambda関数の、IAMロールを作成し、IAMポリシーをアタッチする
③で作成した関数を実行するLambdaのIAMロールに、②で作成したロググループへの書き込み権限を付与します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:CreateLogStream"
],
"Resource": "arn:aws:logs:<region>:<account_id>:log-group:<log_group_name>:*"
}
]
}
以上の手順によって、Lambda自体のログを排したログ出力が可能となります。
IAMユーザーとIAMロールの違いまとめ
項目 | IAMユーザー | IAMロール |
---|---|---|
主体 | 運用者・開発者 | 主にAWSサービス |
権限 | 恒常的 | 一時的 |
使用例 | Lambdaの設定、IAMロールの作成 | LambdaがCloudWatchにログを送る |
参考文献