使用 auth_request 的结果重写 url

使用 auth_request 的结果重写 url

我正在尝试使用 nginx 代理对存储在 S3 上的文件的请求,但是我不想暴露我们的存储桶结构,并且我需要授权用户访问特定文件。除了隐藏存储桶结构外,我已设法使所有功能“正常工作”。

到目前为止,用户将请求https://example.com/s3/FILE_ID,它将被传递到授权部分(使用auth_request)。然后它授权用户,并设置标题Content-Type、S3Authorization标题和其他数据(例如 S3 上的实际位置)。我希望能够rewrite .* $result_from_auth_request,但它似乎不起作用,可能是因为rewriteauth_request发生在不同的阶段?我已经到了可以从 S3 获得响应的地步,但由于我似乎无法更改请求的 URL,S3 授权失败。

基本上,我想映射example.com/s3/FILEIDbucket.s3.amazonaws.com/some/bucket/path/NOT_RELATED_FILE_NAME,但不向用户公开映射。有没有办法根据 的结果重写 url auth_request

这是我的示例配置:

server {
    listen 0.0.0.0:443 ssl http2 default_server;
    root /var/www;
    ssl_certificate /etc/nginx/certs/localhost.crt;
    ssl_certificate_key /etc/nginx/certs/localhost.key;

    location /s3/ {
        # Auth the request first
        auth_request /auth;

        set $bucket mybucket;

        # Request will set these headers which we can pass to S3
        auth_request_set $s3_host $upstream_http_x_s3_host;
        auth_request_set $auth_status $upstream_status;
        auth_request_set $ct $upstream_http_content_type;
        auth_request_set $name $upstream_http_content_disposition;
        auth_request_set $amzAuth $upstream_http_authorization;
        auth_request_set $amzDate $upstream_http_x_amz_date;
        auth_request_set $amzContent $upstream_http_x_amz_content_sha256;
        # The auth handler sets this header as a way of specifying the the location on S3
        auth_request_set $s3path $upstream_http_x_s3_path;

        # Send these to the client so that the file will "download"
        add_header Content-Type $ct;
        add_header Content-Disposition $name;

        proxy_http_version 1.1;
        proxy_hide_header x-amz-id-2;
        proxy_hide_header x-amz-request-id;
        # Set these to send to S3
        proxy_set_header Connection '';
        proxy_set_header Host $bucket.s3.amazonaws.com;
        proxy_set_header Authorization $amzAuth;
        proxy_set_header x-amz-date $amzDate;
        proxy_set_header x-amz-content-SHA256 $amzContent;

        proxy_buffering        off;
        proxy_intercept_errors on;
        proxy_pass_request_headers      off;

        # !!!!---------------
        # Rewrite the url request to S3 to be the "correct" one
        # This doesn't work, "$s3path" always seems to be empty
        # !!!!---------------
        rewrite .* "/$s3path" break;

        resolver 8.8.8.8 valid=300s;
        resolver_timeout 10s;

        recursive_error_pages on;
        error_page 301 302 307 = @handle_redirect;

        proxy_pass https://$s3_host;
    }

    # Sometimes S3 does a redirect, so follow
    location @handle_redirect {
        error_log /dev/stdout debug;
        resolver 8.8.8.8 valid=300s;
        resolver_timeout 10s;

        set $redirect_url $upstream_http_location;
        proxy_pass $redirect_url;
    }

    location = /auth {
        #error_log /dev/stdout debug;

        internal;
        proxy_http_version 1.1;
        proxy_pass http://auth-service:8911/auth;
        proxy_pass_request_body off;
        proxy_set_header        Content-Length "";
        proxy_set_header        X-Original-URI $request_uri;
        proxy_pass_request_headers      on;
    }

    location / {
        #error_log /dev/stdout debug;

        proxy_http_version 1.1;
        proxy_redirect off;
        proxy_read_timeout 6000s;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://app:1854;
    }
}

答案1

我最终将请求传递给 varnish,然后在交给 s3 之前使用它进行 url 重写。(不过,我确实想知道是否有可能在没有 varnish 的情况下使用内部重定向)。

我的配置改变如下:

nginx.conf

upstream varnish_s3 {
    server varnish_cache:80;
}

server {
    listen 0.0.0.0:443 ssl http2 default_server;
    root /var/www;
    ssl_certificate /etc/nginx/certs/localhost.crt;
    ssl_certificate_key /etc/nginx/certs/localhost.key;

    location /s3/ {
        # Auth the request first
        auth_request /auth;

        # Request will set these headers which we can pass to S3
        auth_request_set $s3_host $upstream_http_x_s3_host;
        auth_request_set $auth_status $upstream_status;
        auth_request_set $ct $upstream_http_content_type;
        auth_request_set $name $upstream_http_content_disposition;
        auth_request_set $amzAuth $upstream_http_authorization;
        auth_request_set $amzDate $upstream_http_x_amz_date;
        auth_request_set $amzContent $upstream_http_x_amz_content_sha256;
        # The auth handler sets this header as a way of specifying the the location on S3
        auth_request_set $s3path $upstream_http_x_s3_path;

        # Send these to the client so that the file will "download"
        add_header Content-Type $ct;
        add_header Content-Disposition $name;

        proxy_http_version 1.1;
        proxy_hide_header x-amz-id-2;
        proxy_hide_header x-amz-request-id;
        # Set these to send to S3
        proxy_set_header Connection '';
        proxy_set_header Host $bucket.s3.amazonaws.com;
        proxy_set_header Authorization $amzAuth;
        proxy_set_header x-amz-date $amzDate;
        proxy_set_header x-amz-content-SHA256 $amzContent;
        # Send to varnish
        proxy_set_header X-S3-Path $s3path;

        proxy_buffering        off;
        proxy_intercept_errors on;
        proxy_pass_request_headers      off;

       # resolver 8.8.8.8 valid=300s;
        #resolver_timeout 10s;

        recursive_error_pages on;
        error_page 301 302 307 = @handle_redirect;

        proxy_pass http://varnish_s3;
    }

    # Sometimes S3 does a redirect, so follow
    location @handle_redirect {
        #error_log /dev/stdout debug;

        set $redirect_url $upstream_http_location;
        proxy_pass $redirect_url;
    }

    location = /auth {
        #error_log /dev/stdout debug;

        internal;
        proxy_http_version 1.1;
        proxy_pass http://auth-service:8911/auth;
        proxy_pass_request_body off;
        proxy_set_header        Content-Length "";
        proxy_set_header        X-Original-URI $request_uri;
        proxy_pass_request_headers      on;
    }

    location / {
        #error_log /dev/stdout debug;

        proxy_http_version 1.1;
        proxy_redirect off;
        proxy_read_timeout 6000s;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://app:1854;
    }
}

varnish.default.vcl

vcl 4.0;

backend s3 {
    .host = "s3.amazonaws.com";
    .port = "80";
}

sub vcl_recv {
    if (req.http.X-S3-Path) {
        set req.url = req.http.X-S3-Path;
        return (pipe);
    }
    return (synth(401, "Forbidden"));
}

sub vcl_pipe {
    unset bereq.http.x-s3-path;
    unset bereq.http.x-varnish;
    unset bereq.http.x-forwarded-for;
}

相关内容