📜 ⬆️ ⬇️

Proxy files from AWS S3 using nginx

It would seem that the task of implementing frontend for AWS on nginx sounds like a typical case for StackOverflow - after all, there can be no problems with proxying files from S3? In fact, it turned out that a ready-made solution is not so easy to find, and this article should correct this situation.



Why is this even necessary?


  1. File access control by means of nginx is relevant for the concept of IaC (infrastructure as a code). All changes related to access will be made only in the configurations that are in the project.
  2. If you give files through your nginx, it becomes possible to cache them and thereby save on requests to S3.
  3. Such a proxy will help to abstract from the type of file storage for different installations of the application (after all, in addition to S3, there are other solutions).

Formulate the framework



We are looking for a solution in the forehead


If your original bucket is public, then no difficulty threatens you, proxy requests for S3 and everything will work. If it is private, then you have to somehow authenticate to S3. What do colleagues from the Internet offer us:
')
  1. There are examples of the implementation of the authentication protocol using nginx. The solution is good, but unfortunately, it is designed for an outdated authentication protocol ( Signature v2 ), which does not work in some Amazon data centers . If you try to use this solution, for example, in Frankfurt, you will get the error “The authorization mechanism you have not provided. Please use AWS4-HMAC-SHA256 " . The more recent version of the protocol ( Signature v4 ) is much more difficult to implement, and there are no ready solutions for nginx with it.
  2. There is a third-party module for nginx - ngx_aws_auth . Judging by the source code, it supports Signature v4. However, the project looks abandoned: more than a year there are no changes in the code base, and there is also a compatibility issue with other modules to which the developer does not respond. In addition, adding additional modules to nginx is in itself often a painful step.
  3. You can use a separate s3 proxy, of which quite a lot has been written. Personally, I liked the Go solution - aws-s3-proxy : it has a ready and quite popular DockerHub image. But in this case, the application will acquire another component with its potential problems.

Applying AWS Bucket Policy


AWS, as a rule, scares new users with its complexity and documentation. But if you look at it, you realize that it is very logical and flexible. In Amazon, there was a solution for our task - the S3 Bucket Policy . This mechanism allows building flexible authorization rules for a bucket based on various parameters of a client or request.


Policy Generator Interface - AWS Policy Generator

Here are some interesting parameters to which you can become attached:


Binding to IP is a good option only if the application has a specific place of residence, but in our time it is a rarity. Accordingly, you need to be attached to something else. As a solution, I propose to generate a secret User-Agent or Referer and give the files only to those users who know the secret header. This is what this policy looks like:

 { "Version": "2012-10-17", "Id": "http custom auth secret", "Statement": [ { "Sid": "Allow requests with my secret.", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::example-bucket-for-habr/*", "Condition": { "StringLike": { "aws:UserAgent": [ "xxxyyyzzz" ] } } } ] } 

A bit of explanation:


And this is how the operation of this rule looks like from the point of view of an anonymous user:

 $ curl -I https://s3.eu-central-1.amazonaws.com/example-bucket-for-habr/hello.txt HTTP/1.1 403 Forbidden $ curl -I https://s3.eu-central-1.amazonaws.com/example-bucket-for-habr/hello.txt -H 'User-Agent: xxxyyyzzz' HTTP/1.1 200 OK 

It remains to configure nginx for proxying:

  location /s3-media/ { limit_except GET { deny all; } set $aws_bucket "example-bucket-for-habr"; set $aws_endpoint "s3.eu-central-1.amazonaws.com:443"; set $aws_custom_secret "xxxyyyzzz"; proxy_set_header User-Agent $aws_custom_secret; rewrite ^/s3-media/(.*)$ /$aws_bucket/$1 break; proxy_buffering off; proxy_pass https://$aws_endpoint; } 

Conclusion


Total, having once written a simple policy for a bucket, we were able to safely proxy files using nginx. At the same time, we are not bound by IP and do not depend on additional software.

PS


Read also in our blog:

Source: https://habr.com/ru/post/426739/


All Articles