🪣

MinIOのポリシーを試してみた

2024/09/29に公開

MinIOのポリシーをいじる

最近MinIOのことばかり書いていますが、まだまだやることはいっぱいあります。

次はポリシーの理解です。

ポリシーは「誰に」「何をさせる(させない)」を決める重要なものです。

では早速やっていきます。最初のデータ構造は以下のとおりです。
ここでは、Alias に defaultという名前のものを使用しています。

$ mc tree -f default/
default/
├─ test
└─ test2

Allow と Deny

ポリシーにはAllow(許可)とDeny(不許可)があり、Denyのほうが強いという原則があるようです。

早速試しましょう。ポリシーの作成は面倒なのでツールを使います。MinIOはS3互換なので、S3のポリシージェネレータのご厄介になります。

https://awspolicygen.s3.amazonaws.com/policygen.html

では、まずはtestディレクトリを可視化します。

ポリシーはジェネレータからの出したては次のとおりです。

{
  "Id": "Policy1727568814573",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1727568786966",
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::test",
      "Principal": {
        "AWS": [
          "a"
        ]
      }
    },
    {
      "Sid": "Stmt1727568813060",
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Deny",
      "Resource": "arn:aws:s3:::test2/",
      "Principal": {
        "AWS": [
          "b"
        ]
      }
    }
  ]
}

このときPrincipalは適当で良いです。なぜならMinIOに食わせると消えてしまうからです。

実際に食わせてみましょう。今回は速くやるためにWebコンソールを使用します。
ログインして、左ペインの[Policies]を押して右上の[Create Policy]を押します。

適当な名前をつけて、先程のポリシーのJSONをペーストして[Save]します。

ポリシー(今回は20240929-001)ができました。では実験してみましょう。
左ペインから[Users]を押し、ターゲットにしたいユーザを選択します。

ユーザの選択が終わると[Policies]が選択できますので、右上の[Assing Policies]を押して先程のポリシーを選択して[Save]します。

上記のポリシーでは、testバケットを表示してtest2バケットを表示させないということを設定しました。どうなるか mc treeコマンドで確認しましょう。

$ mc tree -f default/
default/
└─ test

うまくtest2バケットは表示されていません。では、このtest2バケットを表示させようとしてこのDenyを打ち消すためのAllowを書いてみましょう。

{
    "ID": "Policy1727568814573",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1727568786966",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::test/"
            ]
        },
        {
            "Sid": "Stmt1727568813060",
            "Effect": "Deny",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::test2/"
            ]
        },
        {
            "Sid": "Stmt1727568813060",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::test2/"
            ]
        }
    ]
}

ではもう一度見てみましょう。

$ mc tree -f default/
default/
└─ test

やはりtest2は出てきません。おそらくAllowよりDenyのほうが強いのではないかということがわかりました。

Put と Get と Delete

では、実際にはどうやってデータのUploadとDownloadを制御しているか見ていきましょう。
その制御には

  • PutObject
  • GetObject
  • DeleteObject

の3つのアクションがあります。これを駆使して権限をつけていくことができそうです。
まずは、PutObjectから見ていきます。
ポリシージェネレータを使用して以下のJSONを得ます。

{
  "Id": "Policy1727570435755",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1727570434107",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::test/dir1/",
      "Principal": {
        "AWS": [
          "a"
        ]
      }
    }
  ]
}

これをMinIOの20240929-001のポリシーの[Raw Policy]の欄に上書きして貼り付けて[Save]します。

そうするとポリシーが上書きされてtestバケットのdir1に書き込み権限ができます。

実際に書き込んでみましょう。まずは[dir1]のディレクトリを用意します。

$ mkdir dir1

次にmc cpコマンドでコピーしていきます。

$ mc cp dir1 default/test/
mc: <ERROR> Unable to prepare URL for copying. To copy or move 'dir1' the --recursive flag is required.

おっと--recursiveフラグをつけろと言われてしましました。そこでそのフラグ(の短縮形)をつけます。

$ mc cp -r dir1 default/test/
mc: <ERROR> Unable to prepare URL for copying. Unable to guess the type of copy operation.

あれれ、コピーできませんでした。コピー元にデータが入っていないからかもしれません、ですので

$ touch dir1/test.txt

でデータを作成してもう一度やってみました。

$ mc cp -r dir1 default/test/
mc: <ERROR> Failed to copy `/home/evakichi/dir1/test.txt`. Insufficient permissions to access this path `https://FQDN:9000/test/dir1/test.txt`

パーミッションがないと言われてしまいました。もう一度ポリシーを眺めてみましょう、今度はMinIOが保持しているJSONを見てみます。

{
    "ID": "Policy1727570435755",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1727570434107",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::test/dir1/"
            ]
        }
    ]
}

微妙ですが、Resourceが、"arn:aws:s3:::test/dir1/"になっています。これを "arn:aws:s3:::test/dir1/test.txt"にしてみましょう。

{
    "ID": "Policy1727570435755",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1727570434107",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::test/dir1/test.txt"
            ]
        }
    ]
}

では実験です。

$ mc cp -r dir1 default/test/
 0 B / ? ┃░░░░░░░░░░░░░-略-

うまくコピーできたみたいですね、ディレクトリをコピーするときは

  • arn(Amazon Resource Name)をしっかりと書く
  • ディレクトリの中身を空にしない

ということが大事みたいです。
ではこのファイルを消してみましょう。ポリシーをちょっといじって[Save]して、test.txtをダウンロードできるようにしてみましょう。

{
    "ID": "Policy1727570435755",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1727570434107",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::test/dir1/test.txt"
            ]
        }
    ]
}

これでコピーができるはずです。

$ mc cp default/test/dir1/test.txt ./
 0 B / ? ┃░░░░░░░░░░░░░░░░░░░░░░░░░░-略-

コピーできたみたいです。では、最後に消してみましょう。ポリシーをまたいじって[Save]します。
まずはデータの確認。

$ mc tree -f default
mc: <ERROR> Unable to tree. Access Denied.

おっと、ListBukcetを消してしまったのでこうなってしまいました。きちんと書かないとだめですね。
次のようになります。

{
  "Id": "Policy1727572079339",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1727572040319",
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::test/",
      "Principal": {
        "AWS": [
          "a"
        ]
      }
    },
    {
      "Sid": "Stmt1727572077989",
      "Action": [
        "s3:DeleteObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::test/dir1/test.txt"
      "Principal": {
        "AWS": [
          "a"
        ]
      }
    }
  ]
}

これを食わせてみます。

$ mc tree -f default
default
└─ test
   └─ dir1
      └─ test.txt

では、消してみます。

$ mc rm default/test/dir1/test.txt
mc: <ERROR> Failed to remove `default/test/dir1/test.txt`. Insufficient permissions to access this path `https://FQDN:9000/test/dir1/test.txt`

パーミッションがだめといって怒られました。ですのでちょっといじってGetObjectを入れると…。

{
    "ID": "Policy1727572079339",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1727572040319",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::test/"
            ]
        },
        {
            "Sid": "Stmt1727572077989",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::test/dir1/test.txt"
            ]
        }
    ]
}
$ mc rm default/test/dir1/test.txt
Removed `default/test/dir1/test.txt`.

うまく行ったようです。DeleteObjectを使うときはどうやらGetObjectも必要そうです。
ちなみに、ディレクトリの中に何もないとディレクトリは消されてしまうようです。

終わりに

これ以外にも時刻で動作する方法もあります(例えば時刻の範囲指定など)。なので、もうすこしいじってみようと思います。

余談ですが、PutObject``GetObject``DeleteObjectはまとめて*Objectとかけるようです。

Discussion