AWS ParallelCluster 複数のS3バケットへのアクセス設定

ParallelClusterの設定ファイルでS3バケットへのアクセス制限、設定方法を検証しました。
2021.04.09

AWS ParallelClusterで複数のS3バケットを利用したい場合、ParallelClusterの設定ファイルにどのように記述するとクラスターの運用をしやすいのか検証しました。

Icons made by Freepik from www.flaticon.com

結論

  • s3_read_resourceと、s3_read_write_resourceで指定するS3バケットは各々複数指定できない
    • ただし、ワイルドカードを使えば複数バケットも指定できる
      • 例)s3_read_resource = arn:aws:s3:::*
  • 複数のS3バケットへ細かいアクセス制限するにはadditional_iam_policiesで任意のIAMポリシーを指定する
  • 任意のIAMポリシー内に複数S3バケットへのアクセス権限を設定して利用する

Icons made by Freepik from www.flaticon.com

検証環境

ParallelClusterの設定項目である、読み取り専用のs3_read_resourceと、読み書きできるs3_read_write_resourceの設定書式は同じです。

本検証では読み取り専用のs3_read_resourceを例にあげています。 読み書きできるs3_read_write_resourceに置き換えていただいても設定方法は変わりありません。

項目
ParallelCluster 2.10.3
OS Ubuntu 18.04 LTS
AMI aws-parallelcluster-2.10.3-ubuntu-1804-lts-hvm-x86_64-202103172101
Architecture Intel
HeadNode t3.micro
ComputeNode c5.large

S3バケットアクセス制御

Postainstallの説明からはじめます。カスタムブートストラップアクションとしてクラスター起動後にスクリプトを実行してクラスターの環境構築、ライブラリのインストールなど主にコンピュートノードのセットアップします。ParallelClusterではpostinstall scriptの機能で実現しています。

postinstall scripはS3バケットにシェルスクリプトを保存して利用します。ヘッドノード、コンピュートノードは初回起動時にS3バケットからスクリプトを読んで実行します。環境構築に必要なインストールが走る仕組みです。

そのためParallelClusterでHPCクラスターを構築するとpostinstall script保存用にS3バケット1個は必要になります。それ以外のS3バケットに保存してあるデータを取り出したい、計算・解析後にデータを異なるS3バケットに保存したいこともあります。

ParallelClusterの設定ファイルでどのように設定すると都合がよいのか検証します。

Working with Amazon S3 - AWS ParallelCluster

S3バケット情報

S3バケットを3個作成しました。各バケットにはテストファイルを保存してあります。

# Aバケット
$ s3-tree blog-sample-bucket-a
blog-sample-bucket-a
├── a.txt
└── postinstall.sh

0 directories, 2 files

# Bバケット
$ s3-tree blog-sample-bucket-b
blog-sample-bucket-b
└── b.txt

0 directories, 1 file

# Cバケット
$ s3-tree blog-sample-bucket-c
blog-sample-bucket-c
└── c.txt

0 directories, 1 file

S3バケット1個へ読み取り専用アクセス

s3_read_resourceの項目にARNを指定してS3バケットへのアクセス権限を与えます。

Amazon リソースネーム (ARN) - AWS 全般のリファレンス

S3バケット名を1個指定してみます。

書式

s3_read_resource = arn:aws:s3:::[S3バケット名]/*

設定ファイル

以下のParallelClusterの設定ファイルでクラスターを作成しました。

# v2.10.3
[aws]
aws_region_name = us-east-1

[aliases]
ssh = ssh {CFN_USER}@{MASTER_IP} {ARGS}

[global]
cluster_template = default
update_check = true
sanity_check = true

[cluster default]
key_name = sandbox-key-useast1
scheduler = slurm
# --- HeadNode Setting ---
base_os = ubuntu1804
master_instance_type = t3.micro
master_root_volume_size = 30
# --- Netowrk Setting ---
vpc_settings = default
# --- Compute Setting ---
queue_settings = spot1
# --- PostInstall Setting ---
s3_read_resource = arn:aws:s3:::blog-sample-bucket-a/*
post_install = s3://blog-sample-bucket-a/postinstall.sh

tags = { "Name" : "Blog-Sample-ClusterOK" }

[vpc default]
vpc_id = vpc-07edfc27679c9ca80
master_subnet_id = subnet-0ab2754446b2f87a4
compute_subnet_id = subnet-0ab2754446b2f87a4
use_public_ips = true # 検証用設定: パブリックサブネットで起動しているため

[queue spot1]
compute_resource_settings = spot1_resource
placement_group = DYNAMIC
compute_type = spot

[compute_resource spot1_resource]
instance_type = c5.large
max_count = 16

S3バケットアクセステスト

ヘッドノードからaws s3コマンドでS3バケットへアクセスしてチェックします。

Aバケットには読み取りアクセス権があるためダウンロードできました。

$ aws s3 cp s3://blog-sample-bucket-a/a.txt .
download: s3://blog-sample-bucket-a/a.txt to ./a.txt

Aバケットへアップロードは権限がないためできません。

$ touch headnodet.txt
$ aws s3 cp ./headnodet.txt s3://blog-sample-bucket-a
upload failed: ./headnodet.txt to s3://blog-sample-bucket-a/headnodet.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Deniedk

Bバケットには権限がないためダウンロードはできません。

$ aws s3 cp s3://blog-sample-bucket-b/b.txt .
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden

ParallelClusterのIAMロール確認

s3_read_resourceの設定を入れるとIAMポリシー名S3Readが追加されます。設定ファイル内で指定したS3バケット名がResourceに登録されています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::blog-sample-bucket-a/*"
            ],
            "Effect": "Allow",
            "Sid": "S3Read"
        }
    ]
}

2バケットへ読み取り専用アクセス NGパターン

Bバケットにもアクセスしたいので以下の書式で設定ファイルを変更します。

NGパターンS3バケット指定の書式

s3_read_resource = arn:aws:s3:::blog-sample-bucket-a/*, arn:aws:s3:::blog-sample-bucket-b/*

設定ファイル

以下の設定ファイルでクラスターを作成しました。

# v2.10.3
[aws]
aws_region_name = us-east-1

[aliases]
ssh = ssh {CFN_USER}@{MASTER_IP} {ARGS}

[global]
cluster_template = default
update_check = true
sanity_check = true

[cluster default]
key_name = sandbox-key-useast1
scheduler = slurm
# --- HeadNode Setting ---
base_os = ubuntu1804
master_instance_type = t3.micro
master_root_volume_size = 30
# --- Netowrk Setting ---
vpc_settings = default
# --- Compute Setting ---
queue_settings = spot1
# --- PostInstall Setting ---
s3_read_resource = arn:aws:s3:::blog-sample-bucket-a/*, arn:aws:s3:::blog-sample-bucket-b/*
post_install = s3://blog-sample-bucket-a/postinstall.sh

tags = { "Name" : "Blog-Sample-ClusterNG" }

[vpc default]
vpc_id = vpc-07edfc27679c9ca80
master_subnet_id = subnet-0ab2754446b2f87a4
compute_subnet_id = subnet-0ab2754446b2f87a4
use_public_ips = true # 検証用設定: パブリックサブネットで起動しているため

[queue spot1]
compute_resource_settings = spot1_resource
placement_group = DYNAMIC
compute_type = spot

[compute_resource spot1_resource]
instance_type = c5.large
max_count = 16

S3バケットアクセステスト

Aバケットからダウンロードができなくなりました。

$ aws s3 cp s3://blog-sample-bucket-a/a.txt .
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden

Bバケットからダウンロードができないのは同じです。

$ aws s3 cp s3://blog-sample-bucket-b/b.txt .
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden

Aバケットからダウンロードできなくなった原因を確認します。

ParallelClusterのIAMロール確認

ヘッドノードのIAMロールを確認します。IAMロールはpcluster createコマンドでクラスター作成時に生成され、ヘッドノードと、コンピュートノードに割り当てられます。

Resourceで指定する書式が誤っています。s3_read_resourceで指定した内容がそのまま反映されています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::blog-sample-bucket-a/*, arn:aws:s3:::blog-sample-bucket-b/*"
            ],
            "Effect": "Allow",
            "Sid": "S3Read"
        }
    ]
}

本来は下記の書式でIAMポリシーが作成されることを期待していました。ParallelClusterの設定ファイルでは複数のS3バケット登録には対応していないことがわかりました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::blog-sample-bucket-a/*",
                "arn:aws:s3:::blog-sample-bucket-b/*"
            ],
            "Effect": "Allow",
            "Sid": "S3Read"
        }
    ]
}

S3バケットアクセステスト

手動でIAMポリシーを修正するとヘッドノードでダウンロードできるようになりました。しかし、ParallelClusterで管理している設定と乖離が生まれます。次により良いS3バケットの指定方法を考えます。

# AバケットOK
$ aws s3 cp s3://blog-sample-bucket-a/a.txt .
download: s3://blog-sample-bucket-a/a.txt to ./a.txt
# BバケットOK
$ aws s3 cp s3://blog-sample-bucket-b/b.txt .
download: s3://blog-sample-bucket-b/b.txt to ./b.txt
# CバケットNG
$ aws s3 cp s3://blog-sample-bucket-c/c.txt .
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden

2バケットへ読み取り専用アクセス OKパターン

先に必要な権限を与えたIAMポリシーを作成します。Aバケット、Bバケットへ読み取り専用のIAMポリシーを作りました。ヘッドノードからaws s3 lsコマンドでバケット名を確認したいのでS3バケット全体に対してリストは許可しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListAllMyBuckets",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:GetObjectACL"
            ],
            "Resource": [
                "arn:aws:s3:::blog-sample-bucket-a",
                "arn:aws:s3:::blog-sample-bucket-a/*",
                "arn:aws:s3:::blog-sample-bucket-b",
                "arn:aws:s3:::blog-sample-bucket-b/*"
            ]
        }
    ]
}

設定ファイル

additional_iam_policiesの項目に作成したIAMポリシーのARNを指定します。s3_read_resourceはコメントアウトしました。作成したIAMポリシーでAバケットへの読み取り権限があります。

# v2.10.3
[aws]
aws_region_name = us-east-1

[aliases]
ssh = ssh {CFN_USER}@{MASTER_IP} {ARGS}

[global]
cluster_template = default
update_check = true
sanity_check = true

[cluster default]
key_name = sandbox-key-useast1
scheduler = slurm
# --- HeadNode Setting ---
base_os = ubuntu1804
master_instance_type = t3.micro
master_root_volume_size = 30
# --- Netowrk Setting ---
vpc_settings = default
# --- Compute Setting ---
queue_settings = spot1
# --- PostInstall Setting ---
# s3_read_resource = arn:aws:s3:::blog-sample-bucket-a/* # コメントアウトしました
post_install = s3://blog-sample-bucket-a/postinstall.sh

 --- IAM Policy---
additional_iam_policies = arn:aws:iam::[YOUR_ACCOUNT_ID]:policy/BlogSampleParallelclusterPolicy

# --- Tag ---
tags = { "Name" : "Blog-Sample-ClusterPolicy" }

[vpc default]
vpc_id = vpc-07edfc27679c9ca80
master_subnet_id = subnet-0ab2754446b2f87a4
compute_subnet_id = subnet-0ab2754446b2f87a4
use_public_ips = true

[queue spot1]
compute_resource_settings = spot1_resource
placement_group = DYNAMIC
compute_type = spot

[compute_resource spot1_resource]
instance_type = c5.large
max_count = 16

S3バケットアクセステスト

ParallelClusterで自動作成されるIAMロールに独自に作成したIAMポリシーがアタッチされて、クラスターが作成されます。

# AバケットOK
$ aws s3 cp s3://blog-sample-bucket-a/a.txt .
download: s3://blog-sample-bucket-a/a.txt to ./a.txt
# BバケットOK
$ aws s3 cp s3://blog-sample-bucket-b/b.txt .
download: s3://blog-sample-bucket-b/b.txt to ./b.txt
# CバケットNG
$ aws s3 cp s3://blog-sample-bucket-c/c.txt .
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden

ワイルドカード指定

s3_read_resourceまたはs3_read_write_resourceにはS3バケットのARNを1つ指定することがわかりました。 ARNで指定する箇所にワイルドカードを使うと複数のバケットに許可を与えることができます。

以下の例ではすべてのS3バケットに読み取り専用の権限を与えられます。

s3_read_resource = arn:aws:s3:::*

S3バケットアクセステスト

ParallelClusterの設定ファイルは省略します。この設定ファイルから作成したクラスターのヘッドノードでS3バケットのアクセスをテストしました。ABCすべてのバケットのファイルをダウンロードできています。

ABCバケット以外のS3バケットにも読み取り権限があるためセキュリティを考慮した上で指定方法をご検討ください。

# AバケットOK
$ aws s3 cp s3://blog-sample-bucket-a/a.txt .
download: s3://blog-sample-bucket-a/a.txt to ./a.txt
# BバケットOK
$ aws s3 cp s3://blog-sample-bucket-b/b.txt .
download: s3://blog-sample-bucket-b/b.txt to ./b.txt
# CバケットOK
$ aws s3 cp s3://blog-sample-bucket-c/c.txt .
download: s3://blog-sample-bucket-c/c.txt to ./c.txt

まとめ

s3_read_resourceと、s3_read_write_resourceにS3バケットを,(カンマ)区切りで連ねても生成されるIAMポリシーの書式に誤りがある(ParallelClusterの設定ファイルで対応していない)

S3バケットへのアクセスを制限したいときはadditional_iam_policiesに自作のIAMポリシーを指定してクラスターを作成する必要がある。

指定するIAMポリシーはS3バケット以外にも自由に設定できるため、必要に応じてその他AWSリソースへの権限付与し柔軟なクラスター環境が構築できる。

個人的なベストプラクティス

s3_read_resourceでpostinstall.shのファイルを保存してある単体のS3バケットを指定する。 postainstall.shは必ずといってもいいくらい利用するため。

インプットデータなどデータソース置き場のS3バケット、解析、演算終了後のデータ保存先のS3バケットへのアクセス制御はIAMポリシーを作成する。 additional_iam_policiesでIAMポリシーを指定するのがクラスター再構築しなくても設定変更できて使い勝手よいです。

IAMポリシーのARNはクラスターで管理されます。IAMポリシーの中身の設定はクラスターで管理外です。クラスター構築後にIAMポリシーの設定内容を変更しても問題ありません。

Icons made by Freepik from www.flaticon.com

IAMポリシーの例

Bバケットは読み取り専用、Cバケットは読み書き可能なIAMポリシーを作成します。ヘッドノードからaws s3 lsコマンドでバケット名を確認したいのでS3バケット全体に対してリストは許可しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListAllMyBuckets",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:GetObjectACL"
            ],
            "Resource": [
                "arn:aws:s3:::blog-sample-bucket-b",
                "arn:aws:s3:::blog-sample-bucket-b/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:DeleteObject",
                "s3:ListBucket",
                "s3:GetObject",
                "s3:PutObject",
                "s3:GetObjectVersion",
                "s3:GetObjectACL",
                "s3:PutObjectACL"
            ],
            "Resource": [
                "arn:aws:s3:::blog-sample-bucket-c",
                "arn:aws:s3:::blog-sample-bucket-c/*"
            ]
        }
    ]
}

ParallelClusterの設定ファイル

s3_read_resourceでpostainstall.shの保存してあるAバケットを指定しました。 additional_iam_policiesで作成したIAMポリシー名を指定して、クラスターを作成します。

s3_read_resource = arn:aws:s3:::blog-sample-bucket-a/*
post_install = s3://blog-sample-bucket-a/postinstall.sh
additional_iam_policies = arn:aws:iam::[YOUR_ACCOUNT_ID]:policy/[IAM_POLICY]

S3バケットアクセステスト

Cバケットだけはアップロードもできているので意図通りです。

# Donwload
## AバケットOK
$ aws s3 cp s3://blog-sample-bucket-a/a.txt .
download: s3://blog-sample-bucket-a/a.txt to ./a.txt
## BバケットOK
$ aws s3 cp s3://blog-sample-bucket-b/b.txt .
download: s3://blog-sample-bucket-b/b.txt to ./b.txt
## CバケットOK
$ aws s3 cp s3://blog-sample-bucket-c/c.txt .
download: s3://blog-sample-bucket-c/c.txt to ./c.txt

# Upload
## AバケットNG
$ aws s3 cp a.txt  s3://blog-sample-bucket-a/
upload failed: ./a.txt to s3://blog-sample-bucket-a/a.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
## BバケットNG
$ aws s3 cp a.txt  s3://blog-sample-bucket-b/
upload failed: ./a.txt to s3://blog-sample-bucket-b/a.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
## CバケットOK
$ aws s3 cp a.txt  s3://blog-sample-bucket-c/
upload: ./a.txt to s3://blog-sample-bucket-c/a.txt

おわりに

ParallelClusterの設定ファイルで管理されるリソースから切り離すと柔軟性を持たせられます。ただ、管理が煩雑になるので悩みどころです。PoCではじめる場合は余り悩まずParallelCluster設定ファイルで作成できるものは利用した方がよいでしょう、クラスター作って壊してのトライ&エラーの方が検証がスムーズです。