【问题标题】:how to "allow from hostname" in nginx config如何在 nginx 配置中“允许来自主机名”
【发布时间】:2021-10-25 18:43:55
【问题描述】:

我目前正在我的 nginx.conf 中执行此操作:

allow 1.2.3.4;
deny;

我真正想做的是:

allow my.domain.name;
deny;

即,我希望 nginx 在请求时对 my.domain.name 进行 A 记录查找,如果它与请求来自的 IP 匹配,则允许它。但是,我没有看到任何内置机制来执行此操作。在我开始编写自定义代码之前,有人有本地方法吗?

【问题讨论】:

    标签: nginx


    【解决方案1】:

    ngx_http_rdns_module 满足您的需求:https://www.nginx.com/resources/wiki/modules/rdns/ (https://github.com/flant/nginx-http-rdns)

    总结

    此模块允许对传入连接进行反向 DNS (rDNS) 查找,并通过允许/拒绝规则提供对传入主机名的简单访问控制(类似于 HttpAccessModule 允许/拒绝指令;支持正则表达式)。模块与标准解析器指令定义的 DNS 服务器一起使用。

    示例

    location / {
        resolver 127.0.0.1;
    
        rdns_deny badone\.example\.com;
    
        if ($http_user_agent ~* FooAgent) {
            rdns on;
        }
    
        if ($rdns_hostname ~* (foo\.example\.com)) {
            set $myvar foo;
        }
    
        #...
    }
    

    【讨论】:

    • 如何安装这个模块?
    【解决方案2】:

    这个答案是一个替代方案,它允许从 nginx 解析域,但目标完全相同,能够解析 nginx 配置中包含的 ips。

    1) 创建一个文件allowed-domain.list,其中包含您要授予访问权限的域:

    jean-paul.mydomain.com
    rufus.mydomain.com
    robert.mydomain.com
    

    2) 创建一个 bash 脚本 domain-resolver.sh 为您进行查找:

    #!/usr/bin/env bash
    filename="$1"
    while read -r line
    do
            ddns_record="$line"
            if [[ !  -z  $ddns_record ]]; then
                    resolved_ip=`getent ahosts $line | awk '{ print $1 ; exit }'`
                    if [[ !  -z  $resolved_ip ]]; then
                            echo "allow $resolved_ip;# from $ddns_record"
                    fi
            fi
    done < "$filename"
    

    3) 授予此脚本正确的权限chmod +x domain-resolver.sh

    4) 添加一个生成有效 nginx 配置并重新启动 nginx 的 cron 作业:

    #!/usr/bin/env bash
    /pathtoscript/domain-resolver.sh /pathtodomainlist/allowed-domain.list > /pathtooutputdir/allowed-ips-from-domains.conf
    service nginx reload > /dev/null 2>&1
    

    这可以是@daily 作业,也可以让它每小时、每分钟、每秒钟运行一次...

    5) 更新您的 nginx 配置以考虑此输出:

    include /pathtooutputdir/allowed-ips-from-domains.conf;
    deny all;
    

    您可以改进这一点,添加一个 ip 格式检查,如果您不想要它,阻止 ipv6,将所有内容分组到一个文件中...

    【讨论】:

    • 这很完美!谢谢,奖励是它很容易设置和添加到 nginx 代理管理器
    • 很容易理解并且工作完美。很好的解决方案!
    【解决方案3】:

    nginx 官方发行版中没有这个功能。因为它可能会严重降低性能。

    第三方模块http://wiki.nginx.org/3rdPartyModules 也不包含此功能。

    【讨论】:

    • 我不认为完全不提供该功能可以归因于性能。显然它更慢,但这应该是我的选择。 (例如,Apache 为我提供了选项,就像访问日志的 DNS 解析一样。)在这种情况下,我非常愿意将进行 DNS 查找所需的时间换成一个只会被使用的功能偶尔由一个人。所以我想我要自己写了。
    • 此外 - 如果它只在配置加载时查找主机名,这将是有用的。这将消除任何性能考虑,同时提高配置文件的可维护性,...
    【解决方案4】:

    您可以使用 lua 脚本。 您需要安装 nginx-mod-http-lua 和 lua-nginx-dns 模块。 示例 nginx lua 脚本将是:

            location /test/ {
                    access_by_lua_block {
                            local resolver = require "nginx.dns.resolver";
                            local r, err = resolver:new {
                                    nameservers = { "8.8.8.8", "1.1.1.1" },
                                    retrans = 5,    -- timeout retransmits
                                    timeout = 500,  -- 500msec
                                    no_random = true, -- always start from the first name server
                            };
    
                            if not r then
                                    ngx.log(ngx.ERR, "failed to instantiate the DNS resolver: " .. err)
                                    return
                            end
    
                            local answers, err, tries = r:query("my.domain.name", nil, {});
                            if not answers then
                                    ngx.log(ngx.ERR, "failed to query the DNS server: " .. err)
                                    return
                            end
    
                            if answers.errcode then
                                    ngx.log(ngx.ERR, "server returned error code: " .. answers.errcode .. ": " .. answers.errstr)
                                    return;
                            end
    
                            for i, ans in ipairs(answers) do
                                    if ans.address == ngx.var.remote_addr then
                                            return
                                    end
                            end
    
                            ngx.log(ngx.ERR, "Not allow IP : " .. ngx.var.remote_addr);
                            ngx.exit(ngx.HTTP_FORBIDDEN);
                    }
            }
    

    【讨论】:

      猜你喜欢
      • 2017-02-02
      • 2016-03-21
      • 2022-06-15
      • 2019-06-02
      • 2018-11-13
      • 2022-01-17
      • 2012-03-05
      • 1970-01-01
      相关资源
      最近更新 更多