garden/content/articles/20240622204025-对象存储反代设置.md
SouthFox 12506255f0
All checks were successful
/ deploy (push) Successful in 49s
[post] new post
2024-06-22 22:41:32 +08:00

9.1 KiB
Raw Blame History

+++ title = "对象存储反代设置" author = ["SouthFox"] date = 2024-06-22T20:40:00+08:00 lastmod = 2024-06-22T22:40:55+08:00 tags = ["publish"] draft = false +++

为什么要为对象存储做一层反代?

在对象存储商前面挂一层[反向代理]({{< relref "../main/nw_反向代理.md" >}})做一层[缓存]({{< relref "../main/nw_缓存.md" >}})是一个好主意,可以压缩请求数和流量,节省消费开支。同时挡下一些恶意请求。

对象存储很多服务商都是有着「请求数」和「流量」的计费项目,如果被有心之人大量恶意请求那么就有可能产生高额账单。

对策

  • 创建桶名时为其添加随机后缀
  • 最好不要直接使用服务商提供的链接
  • 设置为公开读的桶最好做一层反代

Nginx 反代配置

这里以我所用的 mastadon 所用的配置来举例:

proxy_cache_path /tmp/nginx_mstdn_media levels=1:2 keys_zone=mastodon_media:100m max_size=1g inactive=24h;

   server {
       listen 80;
       listen [::]:80;
       server_name [media-host];
       return 301 https://[media-host]$request_uri;

       access_log /dev/null;
       error_log /dev/null;
   }

   server {
       listen 443 ssl http2;
       listen [::]:443 ssl http2;
       server_name [media-host];

       ssl_certificate /etc/letsencrypt/live/[media-host]/fullchain.pem; # ma>
       ssl_certificate_key /etc/letsencrypt/live/[media-host]/privkey.pem; # >
       include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

       access_log /var/log/nginx/mstdn-media-access.log;
       error_log /var/log/nginx/mstdn-media-error.log;

       location = / {
         return 418;
         }

       location / {
         limit_except GET {
         deny all;
         }
              proxy_cache mastodon_media;
              proxy_cache_revalidate on;
              proxy_buffering on;
              proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
              proxy_cache_background_update on;
              proxy_cache_lock on;
              proxy_cache_valid 30d;
              proxy_cache_valid 404 1h;
              proxy_hide_header 'Access-Control-Allow-Origin';
              proxy_hide_header 'Access-Control-Allow-Methods';
              proxy_hide_header 'Access-Control-Allow-Headers';
              proxy_hide_header x-amz-id-2;
              proxy_hide_header x-amz-request-id;
              proxy_hide_header x-amz-meta-server-side-encryption;
              proxy_hide_header x-amz-server-side-encryption;
              proxy_hide_header x-amz-bucket-region;
              proxy_hide_header x-amzn-requestid;
              proxy_hide_header x-amz-version-id;
              proxy_ignore_headers Set-Cookie;
              proxy_ignore_headers Cache-Control;
              add_header X-Cached $upstream_cache_status;
              add_header 'Access-Control-Allow-Origin' '*';
              expires 1y;
              proxy_pass [s3-url];
       }
    proxy_intercept_errors  on;
    error_page  400 403 404 = @fallback;

    location @fallback {
      return 404;
    }

 }
location = / {
    return 418;
}

如果设置为公开读的桶,那么访问域名主页会列出当下桶前面一些数量的对象,这可能会带来一些风险,所以针对直接访问主页的请求直接拒绝并返回。

limit_except GET {
    deny all;
}

只允许 HTTP GET 方法,毕竟很多对象存储服务是连失败的请求也要计入费用的。

proxy_cache_path /tmp/nginx_mstdn_media levels=1:2 keys_zone=mastodon_media:100m max_size=1g inactive=24h;

...

    proxy_cache mastodon_media;
    proxy_cache_revalidate on;
    proxy_buffering on;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    proxy_cache_background_update on;
    proxy_cache_lock on;
    proxy_cache_valid 30d;
    proxy_cache_valid 404 1h;

nginx 缓存设置,缓存到服务器本地并设置为 30 天有效期

add_header 'Access-Control-Allow-Origin' '*';
expires 1y;
proxy_pass [s3-url];

add_header 放行跨域设置,对于联邦宇宙而言有些实例会直接让用户读取源站媒体,所以不能做限制。

expires 设置客户端的缓存失效时间为一年。

proxy_pass 服务商给的桶公开链接。

proxy_intercept_errors  on;
error_page  400 403 404 = @fallback;

location @fallback {
  return 404;
}

一些服务商的 404 页面里会包含桶名信息,这是一个会被知晓桶名的点。

proxy_intercept_errors 开启后将允许自定义设置错误,将其定位为 nginx 的默认 404 页面。

设置迁移

有时候对一个服务商感到不满准备迁移,例如使用 Rclone 工具将原来的桶拷贝到另一个服务商的桶,对于一个几十上千万的对象的桶来说迁移将是一个漫长的过程。而在迁移时也不可能完全停止服务,但可以在反代层设置一个策略,当找不到对象时可以导向原来的桶,这样对于用户来说也是无感的。具体来说:

  • 更改应用程序配置 s3 设置为新服务商,让新写入数据导向新桶
  • 编辑 nginx 配置,设置反代为新服务商
    • 当新服务商报 404 时,往旧服务商的地址再进行反代
  • 运行迁移,将旧服务商的桶对象拷贝到新服务商的桶内

具体配置:

proxy_cache_path /tmp/nginx_mstdn_media levels=1:2 keys_zone=mastodon_media:100m max_size=1g inactive=24h;

   server {
       listen 80;
       listen [::]:80;
       server_name [media-host];
       return 301 https://[media-host]$request_uri;

       access_log /dev/null;
       error_log /dev/null;
   }

   server {
       listen 443 ssl http2;
       listen [::]:443 ssl http2;
       server_name [media-host];

       ssl_certificate /etc/letsencrypt/live/[media-host]/fullchain.pem; # ma>
       ssl_certificate_key /etc/letsencrypt/live/[media-host]/privkey.pem; # >
       include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

       access_log /var/log/nginx/mstdn-media-access.log;
       error_log /var/log/nginx/mstdn-media-error.log;

       location / {
         limit_except GET {
         deny all;
         }
              proxy_cache mastodon_media;
              proxy_cache_revalidate on;
              proxy_buffering on;
              proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
              proxy_cache_background_update on;
              proxy_cache_lock on;
              proxy_cache_valid 30d;
              proxy_cache_valid 404 1h;
              proxy_hide_header 'Access-Control-Allow-Origin';
              proxy_hide_header 'Access-Control-Allow-Methods';
              proxy_hide_header 'Access-Control-Allow-Headers';
              proxy_hide_header x-amz-id-2;
              proxy_hide_header x-amz-request-id;
              proxy_hide_header x-amz-meta-server-side-encryption;
              proxy_hide_header x-amz-server-side-encryption;
              proxy_hide_header x-amz-bucket-region;
              proxy_hide_header x-amzn-requestid;
              proxy_hide_header x-amz-version-id;
              proxy_ignore_headers Set-Cookie;
              proxy_ignore_headers Cache-Control;
              add_header X-Cached $upstream_cache_status;
              add_header 'Access-Control-Allow-Origin' '*';
              expires 1y;
              proxy_pass [new-s3-url];
       }
    proxy_intercept_errors  on;

    recursive_error_pages on;
    error_page  400 403 404 = @404;

    location @404 {
       proxy_pass [old-s3-url];
       proxy_hide_header 'Access-Control-Allow-Origin';
       proxy_hide_header 'Access-Control-Allow-Methods';
       proxy_hide_header 'Access-Control-Allow-Headers';
       proxy_hide_header x-amz-id-2;
       proxy_hide_header x-amz-request-id;
       proxy_hide_header x-amz-meta-server-side-encryption;
       proxy_hide_header x-amz-server-side-encryption;
       proxy_hide_header x-amz-bucket-region;
       proxy_hide_header x-amzn-requestid;
       proxy_hide_header x-amz-version-id;
       proxy_ignore_headers Set-Cookie;
       proxy_ignore_headers Cache-Control;

       error_page  400 403 404 = @fallback;
    }

    location @fallback {
      return 418;
    }

 }

其中新增加内容并不多:

recursive_error_pages 允许多次定义错误页。

location @fallback {
  return 418;
}

不能再返回 404 了否则会陷入循环,可以另选一个其它错误,这里我选择 418 。

免责声明

安全无小事,我也无法保证上面的设置是没有漏洞的或者完全安全的,对使用相关配置带来的后果也不负任何责任。

参考

Proxying object storage through nginx | Mastodon Docs

云上黑暗森林打爆云账单只需要S3桶名 | Pigsty