はじめに
先日、車のエンジンをかけようとするとかからず、ディーラーの整備の方がたまたま前にいたので聞いてみるとバッテリーがあがってるとのことでした。
最低限エンジンを回しておけば走れるということで、数十分エンジンをかけっぱなしにして、車を走らせてバッテリー交換をしに行きました。
ということで、みなさんこんにちわ。アプリケーションサービス部の森です。
今回は、AWSマネジメントコンソールでAmazon Athenaだけを最小限の権限で利用できるように、やってみます。
最近、Amazon QuickSightを利用することが増え、Amazon S3にファイルを配置してそれを可視化することをやっています。
AWS IAMのドキュメント にもある通り、 最小特権アクセス許可を適用する と記載があるので、
それに準じてやってみようと思います。
では、やってみよう
まずは最小権限を考える
Amazon QuickSightのユーザー管理はAmazon QuickSightで実施するので、今回はAmazon Athenaでクエリを実行できるようにするために必要な権限を確認してみます。
AWS管理ポリシー:AmazonAthenaFullAccess を見る
Amazon Athenaを利用する際の完全なアクセス権限を見て考えます。
ドキュメントは こちら
ドキュメントを見ると、以下のように書かれています。
- Amazon Athenaにフルアクセス(BaseAthenaPermissions)
- AWS Glueへの一部操作権限(BaseGluePermissions)
- Amazon Athenaのクエリ結果を保存するAmazon S3バケットへの操作権限(BaseQueryResultsPermissions)
- Amazon Athenaで読み込むデータ(ファイル)をAmazon S3から読み込む権限(BaseAthenaExamplesPermissions)
- Amazon S3 バケットの一覧表示を許可する権限(BaseS3BucketPermissions)
- Amazon SNSのトピック一覧や属性取得などが可能でモニタリングおよびアラートを利用できる権限(BaseSNSPermissions)
- Amazon CloudWatch Alamrsの作成、読み込み、削除を許可する権限(BaseCloudWatchPermissions)
- AWS Lake Formationに登録されているデータレイクの場所にあるデータにアクセスできる権限(BaseLakeFormationPermissions)
- Amazon DataZoneプロジェクト、ドメイン、環境を一覧表示できる権限(BaseDataZonePermissions)
- AWS Billing and Cost Managementへアクセスできる権限(BasePricingPermissions)
色々ありますね。
Amazon Athenaを利用するために、AWS Glueの権限が必要というのがわかりました。
Amazon SNS、Amazon CloudWatch、AWS Lake Formation、Amazon DataZone、AWS Billing and Cost Managementについては、
今回のブログ対象となるAmazon Athenaでクエリを実行するところという点で、アラームやデータレイクへの権限設定などを利用しないため、今回利用対象外にします。
権限を考える
では、今回利用する権限を考えます。
まずは前提条件を定義しておきます。
Amazon Athenaでクエリを実行するには、データベースとテーブルの作成が必要になります。
ただ、データベースは毎度作るようなものではないので、事前にフル権限で作ってしまいます。
利用側としては、あらかじめAmazon S3バケットにファイルを用意して、テーブルを追加するだけでクエリを実行できるようにします。
それとAmazon Athenaでクエリを実行した場合に結果を保存するAmazon S3バケットも事前に作成して、Amazon Athenaに指定しておきます。
また、 AmazonAthenaFullAccess を見たときに確認した6〜10も対象外にします。
では、前提条件を基に、権限を考えます。
- Amazon Athenaへはアクセスしたいのでこのアクセス権限はそのまま付与します。
- AWS Glueについてはデータベースの情報取得やテーブルのCRUDができる権限を付与します。
データベースへの操作は前提条件に書いた通り、事前作成するので不要です。 - Amazon Athenaのクエリ結果保存するためのAmazon S3バケットへの操作は全て必要なのでそのまま付与します。
- Amazon Athenaで読み込むデータ(ファイル)をAmazon S3から読み込む権限はそのまま付与します。
- Amazon S3バケットの一覧表示はテーブル作成のときに利用するのでそのまま付与します。
- これは前提条件から省くので権限は付与しません。
- これは前提条件から省くので権限は付与しません。
- これは前提条件から省くので権限は付与しません。
- これは前提条件から省くので権限は付与しません。
- これは前提条件から省くので権限は付与しません。
ということで、権限について考えることができたので、実際にどのようなポリシーを設定するかを定義します。
権限を定義する
そのまま権限を付与するものと詳細な権限を定義するものがあるので分けて考えます。
1 / 3 / 4 / 5 はそのまま付与するので、 2 について考えます。
{
"Sid": "BaseGluePermissions",
"Effect": "Allow",
"Action": [
"glue:CreateDatabase",
"glue:DeleteDatabase",
"glue:GetDatabase",
"glue:GetDatabases",
"glue:UpdateDatabase",
"glue:CreateTable",
"glue:DeleteTable",
"glue:BatchDeleteTable",
"glue:UpdateTable",
"glue:GetTable",
"glue:GetTables",
"glue:BatchCreatePartition",
"glue:CreatePartition",
"glue:DeletePartition",
"glue:BatchDeletePartition",
"glue:UpdatePartition",
"glue:GetPartition",
"glue:GetPartitions",
"glue:BatchGetPartition",
"glue:StartColumnStatisticsTaskRun",
"glue:GetColumnStatisticsTaskRun",
"glue:GetColumnStatisticsTaskRuns"
],
"Resource": [
"*"
]
},
glue:CreateDatabase / glue:DeleteDatabase / glue:UpdateDatabase はデータベースに対する更新操作なので今回の対象外にします。
それ以外は利用する可能性含め、付与するようにします。
パーティション設定や列統計を利用しない場合は、Partition 、 ColumnStatisticsTaskRun が含まれる権限は不要です。
権限を作る
これまでの情報を基にIAM Policyを作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BaseAthenaPermissions",
"Effect": "Allow",
"Action": [
"athena:*"
],
"Resource": [
"*"
]
},
{
"Sid": "BaseGluePermissions",
"Effect": "Allow",
"Action": [
"glue:GetDatabase",
"glue:GetDatabases",
"glue:CreateTable",
"glue:DeleteTable",
"glue:BatchDeleteTable",
"glue:UpdateTable",
"glue:GetTable",
"glue:GetTables",
"glue:BatchCreatePartition",
"glue:CreatePartition",
"glue:DeletePartition",
"glue:BatchDeletePartition",
"glue:UpdatePartition",
"glue:GetPartition",
"glue:GetPartitions",
"glue:BatchGetPartition",
"glue:StartColumnStatisticsTaskRun",
"glue:GetColumnStatisticsTaskRun",
"glue:GetColumnStatisticsTaskRuns"
],
"Resource": [
"*"
]
},
{
"Sid": "BaseQueryResultsPermissions",
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload",
"s3:CreateBucket",
"s3:PutObject",
"s3:PutBucketPublicAccessBlock"
],
"Resource": [
"arn:aws:s3:::<Amazon Athenaのクエリ結果を保存するAmazon S3のバケット名>"
]
},
{
"Sid": "BaseAthenaExamplesPermissions",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::<Amazon Athenaで利用するデータ(ファイル)を格納するAmazon S3のバケット名>"
]
},
{
"Sid": "BaseS3BucketPermissions",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:ListAllMyBuckets"
],
"Resource": [
"*"
]
}
]
}
動かしてみる
では、実際に動かしてみます。
先程のIAM Policyを作成して、このポリシーを適用したIAM Userを作成します。
そのIAM Userを利用してAWSマネジメントコンソールにログインします。
ログインすると下記図のようになります。(過去にアクセスしたサービスが表示されているのはすでにいろいろ試したためです)
アクセス権が設定されていないものであるため、 アクセス拒否 されているのが確認できます。

実行
テーブルを作成
では、実際にAmazon Athenaのテーブルを作成していきます。
ここではAmazon Athenaのテーブル作成方法は書きませんが、既存のデータベースを利用し、
Amazon S3に配置したCSVファイルと同じカラムを設定して、テーブルを作成しました。
するとエラーが発生しました。
Amazon Athenaでのクエリ結果を保存するバケットへテーブル作成時のクエリ結果を書き込むためのアクセスができないとのことでした。
ということで確認します。
{
"Sid": "BaseQueryResultsPermissions",
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload",
"s3:CreateBucket",
"s3:PutObject",
"s3:PutBucketPublicAccessBlock"
],
"Resource": [
"arn:aws:s3:::<Amazon Athenaのクエリ結果を保存するAmazon S3のバケット名>"
]
},
クエリ結果はS3バケット直下ではなく、フォルダ配下にPutObjectされているので、
Resource に arn:aws:s3:::<Amazon Athenaのクエリ結果を保存するAmazon S3のバケット名>/* が足りてませんでした。
ということで、以下に変更します。
{
"Sid": "BaseQueryResultsPermissions",
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload",
"s3:CreateBucket",
"s3:PutObject",
"s3:PutBucketPublicAccessBlock"
],
"Resource": [
"arn:aws:s3:::<Amazon Athenaのクエリ結果を保存するAmazon S3のバケット名>",
"arn:aws:s3:::<Amazon Athenaのクエリ結果を保存するAmazon S3のバケット名>/*"
]
},
これでテーブル作成を実行すると成功します。 テーブルができたので次に、SELECT文を実行します。
SELECT文を実行
今回は、データを取得したいという目的を達成するため、簡単なSELECT文を発行します。
SELECT * FROM "データベース名"."テーブル名" limit 10;
するとまたもやエラーが発生しました。

データが入っている対象バケットの対象ファイルにアクセスすることができないエラーが発生しています。
{
"Sid": "BaseAthenaExamplesPermissions",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::<Amazon Athenaで利用するデータ(ファイル)を格納するAmazon S3のバケット名>"
]
},
S3バケット配下にあるデータファイルが見えないということで、
Resource に arn:aws:s3:::<Amazon Athenaのクエリ結果を保存するAmazon S3のバケット名>/* が足りてませんでした。
ということで、以下に変更します。
{
"Sid": "BaseAthenaExamplesPermissions",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::<Amazon Athenaで利用するデータ(ファイル)を格納するAmazon S3のバケット名>",
"arn:aws:s3:::<Amazon Athenaで利用するデータ(ファイル)を格納するAmazon S3のバケット名>/*"
]
},
これでクエリが正常に実行されました。

ということで、もう一度修正したものを含めてIAM Policyを書いてみます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BaseAthenaPermissions",
"Effect": "Allow",
"Action": [
"athena:*"
],
"Resource": [
"*"
]
},
{
"Sid": "BaseGluePermissions",
"Effect": "Allow",
"Action": [
"glue:GetDatabase",
"glue:GetDatabases",
"glue:CreateTable",
"glue:DeleteTable",
"glue:BatchDeleteTable",
"glue:UpdateTable",
"glue:GetTable",
"glue:GetTables",
"glue:BatchCreatePartition",
"glue:CreatePartition",
"glue:DeletePartition",
"glue:BatchDeletePartition",
"glue:UpdatePartition",
"glue:GetPartition",
"glue:GetPartitions",
"glue:BatchGetPartition",
"glue:StartColumnStatisticsTaskRun",
"glue:GetColumnStatisticsTaskRun",
"glue:GetColumnStatisticsTaskRuns"
],
"Resource": [
"*"
]
},
{
"Sid": "BaseQueryResultsPermissions",
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket",
"s3:ListBucketMultipartUploads",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload",
"s3:CreateBucket",
"s3:PutObject",
"s3:PutBucketPublicAccessBlock"
],
"Resource": [
"arn:aws:s3:::<Amazon Athenaのクエリ結果を保存するAmazon S3のバケット名>",
"arn:aws:s3:::<Amazon Athenaのクエリ結果を保存するAmazon S3のバケット名>/*"
]
},
{
"Sid": "BaseAthenaExamplesPermissions",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::<Amazon Athenaで利用するデータ(ファイル)を格納するAmazon S3のバケット名>",
"arn:aws:s3:::<Amazon Athenaで利用するデータ(ファイル)を格納するAmazon S3のバケット名>/*"
]
},
{
"Sid": "BaseS3BucketPermissions",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:ListAllMyBuckets"
],
"Resource": [
"*"
]
}
]
}
番外編
では、本当にAmazon Athena以外が利用できないか?をAmazon RDSのインスタンス起動で確かめてみます。
AWSマネジメントコンソールから、Amazon RDSを選択し、データベースの作成ボタンをクリックすると早速エラーが発生しました。
全てのサービスは確認できていませんが、Amazon EC2やAWS Lambdaでも同様にエラーが発生しました。

おわりに
最小権限を設定するのってすごく大変のように見えますが、大変かもしれません。
とは言え、一つずつ理解して設定し、動作を確認していけばなんとかなりそうですね。
某芸能人の方が昔おっしゃっておりましたが、「小さなことからコツコツと」ですね。
他のサービスも一歩一歩着実にクリアしていけそうですので、また機会があれば頑張ってみます。