Deny all location ... except

Francis Daly francis at daoine.org
Mon Oct 26 13:00:10 UTC 2020


On Wed, Oct 21, 2020 at 03:50:03PM -0300, Rejaine Silveira Monteiro wrote:

Hi there,

> I want to deny all access from external network to /prod and /hml
> locations, except from some arguments like  "?TEST" or "=TEST"

I don't see a straightforward way to do this, I'm afraid.

For a non-straightforward way: It is possible to use "map" to create a
variable to indicate whether or not you want this request to be blocked;
and then use that variable instead of your allow/deny lists. But that will
only be useful if you can find patterns that correctly match everything
you want in the block/no-block decision.

(And it is sort-of doing in config, what the application already has
facilities to do -- but your special use case might make that worthwhile.)

> https:/domain.com/prod/*  (allow to localnet, deny to external users), but...
> https:/domain.com/prod/INDEX.apw?op=01&SERVICE=TEST   (allo to all)
> https:/domain.com/prod/INDEX.apw?TEST=123 (allow to all)
> https:/domain.com/prod/something/TEST/index.html (allow to all)

For example, if your version of "localnet" can be expressed in a small
number of regex patterns, then you could try something like

  map "$remote_addr-$request_uri" $block_this_request {
    default 1;
    ~^127\.0\.0\.1-/ 0;
  }

which, when used, would have the effect of allowing everything from
127.0.0.1 and blocking everything else. Your case might want something
like ~^192\.168\. to allow addresses that match that pattern.

(If your "localnet" is not simple, then "geo" might be usable to set an
always-allow variable based on source IP instead; and *that* could be
used in the continuation of this example.)

Next, that same "map" should include whatever patterns you want to allow
from anywhere -- perhaps the string TEST anywhere in the url, or the
string TEST= after a ? in the url; or even a complete list of urls or
url prefixes that you want to allow; and set the $block_this_request
variable to 0 in those cases. For example, for "/TEST/" or "TEST=" or
"=TEST" anywhere in the url, you could add the three lines

  ~/TEST/ 0;
  ~TEST= 0;
  ~=TEST 0;

inside the map.

> I tried to use something like  " if ($args = TEST) {  allow all;}",
> but Nginx gives error " directive is not allowed here"

Now that you have set $block_this_request: in the two location{}s that
you want it to take effect, remove the "allow" and "deny" lines, and
instead add

  if ($block_this_request) { return 403; }

which should have the same effect as the previous deny.

> location /prod  {
>     allow localnet;
>    deny all;
>   proxy_pass http://web1.domain:8080/prod;
> }
> location /hml  {
>    allow localnet;
>    deny all
>   proxy_pass http://web1.domain:8081/hml;
> }
> 
> I appreciate any help

It does not strike me as especially elegant; but if it does what you want,
efficiently enough for your use case, it may be adequate. At least until
someone suggests an alternative.

Good luck with it,

	f
-- 
Francis Daly        francis at daoine.org


More information about the nginx mailing list