2

I want to have nginx for user level access control to specific url,

For other user <uid>, they are limited to access http://myserver.com/<uid> (METHOD POST). like user larrycai can only POST to http://myserver.com/larrycai/xxx.

I don't want to have this control in upstream server.

Basic authentication is used for access authentication like below

server {
    ...
    auth_basic "Auth";
    auth_basic_user_file conf/htpasswd;
}

Now how can I map the authenticated user to its own url ? (I am new to nginx).

My use case is the nginx docker container in front of docker-registry to have better user access control.

UPDATE in 2015.1.11

The uid is not related with unix system, it is for application only, which is mapped to REST interface

Is it possible to use extra module like openresty (lua based) ?

Larry Cai
  • 55,923
  • 34
  • 110
  • 156
  • Your request is a little hard, it's either pass or deny, regardless of the method (there might be a workaround but that would probably involve if conditions), then there's your unix system which can't by any means relate an http request to a system user, so the user based authroization is kinda hard too – Mohammad AbuShady Jan 10 '15 at 17:33
  • thx, update the question to clarify the uid is not related with unix, and it could use extra nginx module – Larry Cai Jan 11 '15 at 13:20
  • I don't have much experience with lua modules, if possible I recommend that you create this authorization logic in your app instead of the websrver it self, would be easier to handle and more maintainable – Mohammad AbuShady Jan 11 '15 at 13:22
  • thx, it could be possible. But that is even tricky for me, since I use official docker registry image directly, I don't want to touch that ;-) – Larry Cai Jan 11 '15 at 13:48
  • Try: https://github.com/casbin/lua-casbin – hsluoyz Mar 26 '21 at 03:33

2 Answers2

9

I have been able to work out a solution to enable many users to pull containers from my docker-registry and only special authorised users to push to my registry using ngx_openresty-1.7.7.1

/usr/local/openresty/nginx/conf/nginx.conf

worker_processes  1;
error_log /var/log/lua.log notice;

events {
   worker_connections  1024;
}

http {
   include       mime.types;
   default_type  application/octet-stream;

   sendfile        on;
   keepalive_timeout  65;
    # For versions of nginx > 1.3.9 that include chunked transfer encoding support
    # Replace with appropriate values where necessary

    upstream docker-registry {
      server localhost:5000;
    }

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;
        #access_log  /var/log/nginx/log/host.access.log  main;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }

    server {
      listen 443;
      server_name docker-registry01.company.com;

      ssl on;
      ssl_certificate /etc/ssl/certs/docker-registry;
      ssl_certificate_key /etc/ssl/private/docker-registry;

      client_max_body_size 0; # disable any limits to avoid HTTP 413 for large image uploads

      # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
      chunked_transfer_encoding on;

      location / {
        auth_basic            "Restricted";
        auth_basic_user_file docker-registry.htpasswd;
        access_by_lua_file 'authorize.lua';

        include               docker-registry.conf;
      }

      location /_ping {
        auth_basic off;
        include               docker-registry.conf;
      }

      location /v1/_ping {
        auth_basic off;
        include               docker-registry.conf;
      }

    }
}

/usr/local/openresty/nginx/conf/docker-registry.conf

proxy_pass                       http://docker-registry;
proxy_set_header  Host           $http_host;   # required for docker client's sake
proxy_set_header  X-Real-IP      $remote_addr; # pass on real client's IP
proxy_set_header  Authorization  ""; # see https://github.com/dotcloud/docker-registry/issues/170
proxy_read_timeout               900;

/usr/local/openresty/nginx/authorize.lua

-- authorization rules

local restrictions = {
  all  = {
    ["^/$"]                             = { "HEAD" }
  },
  user = {
    ["^/$"]                             = { "HEAD", "GET" },
    ["^/v1/search$"]                    = { "HEAD", "GET" },
    ["^/v1/repositories/.*$"]           = { "HEAD", "GET" },
    ["^/v1/images/.*$"]                 = { "HEAD", "GET" }
  },
  admin  = {
    ["^/$"]                             = { "HEAD", "GET" },
    ["^/v1/search$"]                    = { "HEAD", "GET" },
    ["^/v1/repositories/.*$"]           = { "HEAD", "GET", "PUT" },
    ["^/v1/images/.*$"]                 = { "HEAD", "GET", "PUT" }
  }
}

-- list of roles and users
local user_role = {
   all   = {"all"},
   user  = {"user", "user2", "user3", "etc..."},
   admin = {"admin", "dave_albert", "other_admin", "jenkins"}
}

-- get authenticated user as role
local user = ngx.var.remote_user
local role = nil
for _role, user_list in pairs(user_role) do
   for k,user_name in pairs(user_list) do
      if user_name == user then
         role = _role
      end
   end
end

-- exit 403 when no matching role has been found
if restrictions[role] == nil then
  ngx.header.content_type = 'text/plain'
  ngx.status = 403
  ngx.say("403 Forbidden: You don't have access to this resource/role.")
  return ngx.exit(403)
end

-- get URL
local uri = ngx.var.uri

-- get method
local method = ngx.req.get_method()

local allowed  = false

for path, methods in pairs(restrictions[role]) do

  -- path matched rules?
  local p = string.match(uri, path)

  local m = nil

  -- method matched rules?
  for _, _method in pairs(methods) do
    m = m and m or string.match(method, _method)
  end

  if p and m then
    allowed = true
  end
end

if not allowed then
  ngx.header.content_type = 'text/plain'
  ngx.log(ngx.WARN, "Role ["..role.."] not allowed to access the resource  ["..method.." "..uri.."]")
  ngx.status = 403
  ngx.say("403 Forbidden: You don't have access to this resource.")
  return ngx.exit(403)
else
  ngx.log(ngx.WARN, "User ["..user.."] accessing resource ["..method.." "..uri.."]")
end
Dave Albert
  • 1,429
  • 15
  • 21
-1

You can't see, get the user in your config.

You could restrict some access via

location /larrycai {
    deny all;
}

All in all you can not restrict this via nginx. You can write a PHP Script, but that doesn't seem to be what you would like to have.

Cr41s3
  • 97
  • 2
  • 11