AR ホームベーカリー

オイラのアウトプット用ホームベーカリー!

bucket-antivirus-function のバケットポリシー

オリジナルが一年ほど更新されてないしワイも fork して自分用の作っちゃうかなあ、という気持ちになりつつある。

全体公開されているバケットでアクセス制御したい

S3 バケットが全体公開されている状態で、 bucket-antivirus-function でスキャンした結果付与される av-status タグによって、バケット内オブジェクトへのアクセスを制御したい。 具体的なバケットの状態は以下 (複数なのは、開発・統合・検証・本番の 4 環境存在するため)。

f:id:donbulinux:20201210160813p:plain
全体公開されている状態

README のバケットポリシー

リポジトリの example では Deny のものしかないため、今回の要件である S3 オブジェクトを直接ブラウザから参照させるが達成できない。

github.com

全体公開する

そーいう使い方はするなという AWS からの圧も感じるが、Cloudfront で配信するようなアクセスは絶対に発生しない作りなので、あえて静的配信でいく。 明示的に許可するには、以下のようなルールが必要になる。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケット名/*"
        }
    ]
}

しかしこれでは av-status タグの内容に関わらず公開されてしまう。 ので、ここに Condition を追加してこうしてみた。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケット名/*",
            "Condition": {
                "StringEquals": {
                    "s3:ExistingObjectTag/av-status": "CLEAN"
                }
        }
    ]
}

これで av-status タグが CLEAN のオブジェクトだけパブリックアクセスできるやろ! Condition を満たさないオブジェクトは暗黙的な拒否で AccessDenied になるはずや!

docs.aws.amazon.com

拒否される時と拒否されない時がある

なんでや! (なんでや!)

マネジメントコンソールにログインして作業していたのですが、ログインしているアカウントでポリシーを設定したバケットに対して、マネジメントコンソール経由でアップロードしたファイルは制御できていたのですが、既存のファイル (scan_bucket.py で手動酒キャン済み) が Condition の制御から漏れてしまうようでした。

えー、もしかして IAM とかクロスアカウント制御的なヤツなの……? と思ったのですが「単体のワークスペースだしなー」と悩んだ末、これ暗黙的な拒否に期待するのがダメなのでは? という結論に至り。

最終的なバケットポリシー

ポリシー内の明示的な拒否は、すべての許可に優先します。

とのことなので、最初に拒否する条件を書いておいて、マッチしなかったら全体公開する条件が参照されるようにすればいいんじゃねえの?

docs.aws.amazon.com

ということで、明示的に拒否と許可を記載することにしました。 一応 example を尊重して Deny の Action にタグ変更追加してあるけど、これも不要かもしれないっすね。

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": ["s3:GetObject", "s3:PutObjectTagging"],
            "Resource": "arn:aws:s3:::バケット名/*",
            "Condition": {
                "StringEquals": {
                  "s3:ExistingObjectTag/av-status": "INFECTED"
                }
            }
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケット名/*",
            "Condition": {
                "StringEquals": {
                    "s3:ExistingObjectTag/av-status": "CLEAN"
                }
            }
        }
    ]
}

これで、

  1. アクセス対象オブジェクトの av-status タグが INFECTED ならアクセス拒否
    1. の条件に当てはまらなければ、オブジェクトの av-status タグが CLEAN ならアクセス許可

が達成できました。 やったぁ。 けど Allow 時の "s3:ExistingObjectTag/av-status": "CLEAN" で制御されないパターンあるって自分で書いてるし、 Condition は削除しちゃってもいいかもしれないっすね。

ちなみに AWS のポリシーは書いた順番で評価するのではなく、 Deny -> Allow の順で評価されるのと、 Statement 配列は OR 条件らしいです。 クラスメソッドくんいつもありがとー!

dev.classmethod.jp