Using variables on configuration (map?) for regex

Francis Daly francis at daoine.org
Sat Jul 23 08:28:19 UTC 2016


On Fri, Jul 22, 2016 at 08:22:18AM +0200, mostolog at gmail.com wrote:

Hi there,

there are a few different questions that you might be asking, and I'm
not certain which one you are actually asking.

So I'll guess; if I guess wrong, do feel free to reply with other details.

> I'm trying to /clean/ up a config file and I'm having a headache
> trying to do it.

The quick question/answer from the Subject line:

if you are asking: how do I use a $variable in the "does this match" part
of a "map"; the answer is "you don't". $ is either a literal character
(in a string), or the end-of-string metacharacter (in a regex).

> Consider the following scenario:
> 
>  * Users from group gfoo must be allowed to GET URL foo, while adminfoo
>    must be able to POST
>  * Users from group gbar must be allowed to GET URL bar, while adminbar
>    must be able to POST
>  * ...and so on for ~50 groups.

What is a user and group, in this context?

(Your example suggests that your client will send a http header "Groups:
gfoo" if this request should be handled as if this user is in the group
gfoo. Perhaps you are using a special client configuration where that
is true?)

Is the "foo" in each of "group gfoo", "group adminfoo", "url foo" always
identical? As in: can simple pattern-matching work, or do you need an
extra mapping somewhere to tie the names together?

(This may not matter; but if it is important one way or the other and
is *not* included in the problem description, it will probably not be
considered for the solution.)

> The configuration at this moment is similar to:
> 
>    server {
>         listen 80;
>         server_name foo.domain.com;
>         location ~ /content/foo {
>             if ($denied_foo) {
>                 return 403 "Forbidden";
>             }
>             ...
>         }
>         location ~ /page/bar/action...and ~10 locations more per server...
>    }

So that one has foo.domain.com, /content/foo, and /page/bar.

>    server {
>         listen 80;
>         server_name bar.domain.com;
>         location ~ /content/bar {
>             if ($denied_bar) {
>                 return 403 "Forbidden";
>             }
>             ...
>         }
>         location ~ /page/bar/action...and ~10 locations more per server...
>    }

and that one has bar.domain.com, /content/bar, and /page/bar.

Is the /page/bar here the same as the /page/bar in the "foo" section? Or
is the "bar" in /page/bar here the same as the "bar" in /content/bar here?

Possibly it does not matter; but if it does not matter it should probably
not be in the question.

>    ...~200 whatever.domain.com servers more

A bunch of extra servers is not a problem, I think.

>    map $request_method:$request_uri:$http_groups $denied_foo {
>         default 1;
>    ~^GET:/content/foo:gfoo 0;
>         ~^POST:/content/foo:adminfoo 0;
>    }
>    map $request_method:$request_uri:$http_groups $denied_bar {
>         default 1;
>    ~^GET:/content/bar:gbat 0;
>    ~^POST:/content/bar:adminbar 0;
>    }
>    ...lots of map directives

These map directives look wrong to me.

It looks like you should have the $request_uri bit at the end of the
"match against this" expansion, since you presumably want /content/bar
and /content/bar/something both to match the same way.

And it's not clear to me why you have multiple "map" directives. One
that sets the single variable "$denied_group" looks like it should
be enough. One "default" line; two lines per "foo" or "bar". What am
I missing?

> I'll like to be able to simplify it doing something like:
> 
>         server_name (?<myvar>.*)\.domain\.com;

That can work.

>    ...
>    map $request_method:$request_uri:$http_groups $denied {
>         default 1;
>         ~^GET:/content/$myvar:g$myvar 0;
>         ~^POST:/content/$myvar:admin$myvar 0;
>    }

That can't. You would need two lines per "myvar" value -- but since
you must have the list of myvar values somewhere, you should be able to
auto-generate these lines from that list.

> Having ~200 configuration files doesn't seem a good option, so omit
> "on-build config with script parameters"

I'm not immediately seeing the problem with 200 configuration files.

If the problem is "lots of files", then you could concatenate them all
in to one file.

>From the question, it is not not clear to me whether a user in group gbar
should have any access at all to the server foo.domain.com. And it is
not clear to me whether there is anything else available below /content/
other than /content/foo/, in the server foo.domain.com.

Would a configuration along the lines of

==
  server {
    location /content/ {
      if ($denied_group) {
        return 403 "Forbidden";
      }
      ...
    }
    location ~ /page/bar/action...and ~10 locations more per server...
  }
==

do what you want?

Cheers,

	f
-- 
Francis Daly        francis at daoine.org



More information about the nginx mailing list