active storage direct upload issue with s3 encryption

74 Views Asked by At

I've been trying to get active storage working with direct uploads in my react project. Keep getting a 403 because of the 'Deny' in my IAM policy.

I have active storage setup with the following storage.yml file

production:
  service: S3
  bucket: <bucketname>
  region: "us-east-1"
  access_key_id: <access_key>
  secret_access_key: <secret_access_key>
  upload:
    server_side_encryption: "AES256"

I am using the direct upload mentioned here in the rails docs using this package

The IAM policy looks like this

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::<bucket>",
                "arn:aws:s3:::<bucket>/*"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Deny",
            "Action": "s3:PutObject",
            "Resource": [
                "arn:aws:s3:::<bucket>",
                "arn:aws:s3:::<bucket>/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "s3:x-amz-server-side-encryption": "AES256"
                }
            }
        }
    ]
}

My bucket's CORS settings

[
    {
        "AllowedHeaders": [
            "*",
            "x-amz-server-side-encryption"
        ],
        "AllowedMethods": [
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "http://localhost:8000/",
            "http://localhost:8000",
            "http://localhost:8010/"
        ]
    }
]

I've tried every suggestion I can find on google and finally tracked down the issue.

If I remove

{
            "Sid": "VisualEditor1",
            "Effect": "Deny",
            "Action": "s3:PutObject",
            "Resource": [
                "arn:aws:s3:::<bucket>",
                "arn:aws:s3:::<bucket>/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "s3:x-amz-server-side-encryption": "AES256"
                }
            }
        }

from the IAM policy, it works!

But I want the extra security.

My presigned URL I am getting from the rails/active_storage/direct_uploads endpoint looks like this.

https://.s3.amazonaws.com/1fhy070cp9l4oegb3mcq5mta0rgx?x-amz-server-side-encryption=AES256&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...

EDIT: here's the FE code that does the uploading via the rails/activestorage package

const getLogoBlob = (logo: File, callback: (blob: Blob) => void) => {
  const upload = new DirectUpload(
    logo,
    `${env.baseUrl}/rails/active_storage/direct_uploads`,
  );
  upload.create(async (error, blob) => {
    if (error) {
      throw new Error('Failed to upload logo');
    }

    callback(blob);
  });
};

0

There are 0 best solutions below