EC2インスタンスからS3バケットにアクセスして、ファイルのダウンロードやアップロードをする

System ManagerなどでAWS内のEC2インスタンスにアクセスすることは多々ある。そんなとき、S3バケットに必要なファイル（例えば、インストーラやモジュールなどのファイル）を保存し、そのファイルをEC2インスタンスのローカルにダウンロードしたい、またはEC2インスタンスからS3にアップロードしたいといった場面がある。
EC2インスタンスの中でブラウザを立ち上げて、AWSマネジメントコンソールにログインしてS3を開くのもいいが、あまりにも入れ子感があるので、なんとかラクできないかと試行。
S3をFTPサーバに見立てたような使い方をしたいときの方法を記す。

# 前提
EC2インスタンスにIAMロールを割り当て、IAMロール内にIAMポリシーを含めている構成。

# AWS CLIインストール
対象のEC2インスタンスに、AWSCLIをインストールする。
インストール方法は[公式手順](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)より、OSに合わせた手順でインストール。

# IAMポリシー作成
IAMより、以下のポリシーを作成する。
ここでは例として、MyBucket01とMyBucket02という2つのS3バケットに対して許可を与えている。ここで許可を与える操作は、List(ファイルを出力させる）、get（ダウンロード）、put（アップロード）のみに限定。セキュリティ基準に応じて、任意緩くしたりさらに厳しくしたりする。

```json:s3-RW-Allow-IAMpolicy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": [
                "arn:aws:s3:::MyBucket01",
                "arn:aws:s3:::MyBucket02"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": [
                "arn:aws:s3:::MyBucket01",
                "arn:aws:s3:::MyBucket02"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::MyBucket01/*",
                "arn:aws:s3:::MyBucket02/*"
            ]
        }
    ]
}
```

S3バケットがKMSによる暗号化をしている場合がほとんどだと思う。このため、S3の操作をする際は暗号化を解除する権限も付与する。
「"arn:aws:kms:REGIONNAME:AWSAccountID:key/XXXXXXXXXXXXXXXXXXXXXXXXXXX"」の部分は、S3が暗号化しているKMSキーのARNを指定する。※KMSより確認が可能。

```json:s3-RW-Allow-IAMpolicy(S3がKMSありの場合のみ)
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "kms:Decrypt",
                "kms:Encrypt",
                "kms:GenerateDataKey"
            ],
            "Resource": "arn:aws:kms:REGIONNAME:AWSAccountID:key/XXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "Effect": "Allow"
        },
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": [
                "arn:aws:s3:::MyBucket01",
                "arn:aws:s3:::MyBucket02"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": [
                "arn:aws:s3:::MyBucket01",
                "arn:aws:s3:::MyBucket02"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::MyBucket01/*",
                "arn:aws:s3:::MyBucket02/*"
            ]
        }
    ]
}

```

# IAMロール割り当て
作成したIAMポリシーを、IAMロールにアタッチする。

# KMSキーポリシー側の許可(S3バケットをKMS暗号化している場合のみ)
KMSでS3を暗号化している場合のみ、KMS側の「キーポリシー」と呼ばれるJSONでも許可設定をしてやる必要がある。KMSでS3を暗号化していない場合、本項目ごと実施不要。
S3で暗号化している鍵を確認したら、AWSマネジメントコンソールからKey Management Serviceより、その鍵のキーポリシーを編集する。JSONのブロック内に、以下を追記する。以下は一部のみのため、注意。
「"AWS": "arn:aws:iam::AWSAccoutID:role/IAMROLENAME"」はIAMロールのARNを記載、「"Resource": "arn:aws:kms:REGIONNAME:AWSAccoutID:key/KMSKEYID"」はいま編集しているKMSキーのARNとなる。

```json:KMS Key Policy(一部のみ)
        {
            "Sid": "Key for encryption and decryption of KMS on EC2 instance.",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::AWSAccoutID:role/IAMROLENAME"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "arn:aws:kms:REGIONNAME:AWSAccoutID:key/KMSKEYID"
        }
```

これでKMS側キーポリシーと、IAMポリシー側の権限設定が完了し、EC2インスタンスでS3のファイルアップロード、ダウンロードする準備が整った。


# EC2インスタンスでS3を操作する
EC2インスタンスにAWSCLIがインストールされているので、EC2インスタンス内のコマンドからS3を操作する。

## S3バケットのリスト表示
s3://MyBucket01/SubDir01というS3のARNを指定し、その中に何のファイルがあるか一覧出力させている。s3://MyBucket02/SubDir02についても同様の操作。
ちなみに、S3ARNは後ろのスラッシュは必ずつけること。つけないと認識しないため。
```shell-session
$ aws s3 ls s3://MyBucket01/SubDir01/
$ aws s3 ls s3://MyBucket02/SubDir02/
```

## S3バケットへファイルをアップロード
s3://MyBucket01/SubDir01/に対しては、FILENAME01 をアップロード、s3://MyBucket02/SubDir02/に対しては、FILENAME02 をアップロードするコマンド。
```shell-session
$ aws s3 cp FILENAME01 s3://MyBucket01/SubDir01/
$ aws s3 cp FILENAME02 s3://MyBucket02/SubDir02/
```

## S3バケットからファイルをダウンロード
ここでは例として、先ほどアップロードしたFILENAME01とFILENAME02をダウンロードしている。ローカル保存先を任意指定してダウンロードする。

```shell-session
$ aws s3 cp s3://MyBucket01/SubDir01/FILENAME01 ローカル保存先ディレクトリ
$ aws s3 cp s3://MyBucket02/SubDir02/FILENAME02 ローカル保存先ディレクトリ
```

こんな感じで、円滑にAWSで構築などを行うことができる。ただし、S3は保存料がかかるので、使い過ぎは注意。不要なファイルはどんどん消すことが大事。

# 参考
AWS CLI の最新バージョンをインストールまたは更新します。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

AWS CLI で S3 にファイルをアップロード
https://qiita.com/seyself/items/43426f57c50021ea55f8

[AWS] S3を操作するIAM JSON ポリシーのサンプル
https://blog.katsubemakito.net/aws/s3-iam-jsonpolicy

AWS KMS S3バケットをSSE-KMSで暗号化しファイルのアップロード・ダウンロードするときにKMSへ必要なIAMポリシーを確認してみた
https://dev.classmethod.jp/articles/encryption-requires-a-generate-data-key-policy/

AWSのKMSへのアクセスをIAMグループ単位で管理する (KMSキーポリシーでIAMグループが指定できないよ問題)
https://qiita.com/minamijoyo/items/c6c6770f04c24a695081

# 余談
昨年は「トップガンマーヴェリック」が素晴らしい映画だった。当然ブルーレイも買った。今年に入って「RRR」や「アバター2」も見たが、昨年公開した映画という意味では「トップガンマーヴェリック」の凄さには叶わなかった（どれもとても面白かったんだけれども）。
なんというか、映像の凄さもだが、トムクルーズの覚悟、「でもやるんだよ（絶滅するにしても今日じゃない）」精神、リーダーシップに感動。数年に一度の完璧な映画だった。

ここ最近、ChatGPTの圧倒的な能力を見るに、「人類の黄昏時代がやってきたか・・・」なんて感じることが多いけど、トムクルーズの「でも今日じゃない」精神を見習って、あがいていきたい。
そしてあがきつつも、GPT-4にお布施して業務効率化を図ろうと思う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/07acd550-97ab-4b82-4533-0c2c5a15d980.png)