Navigation

    Netgate Discussion Forum
    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search

    Problem using webroot local folder - hash file not created

    ACME
    acme
    3
    6
    188
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      Bill Harris last edited by

      I'm trying to set up the acme plugin with the webroot local folder method in conjunction with haproxy and the LUA script from [https://github.com/janeczku/haproxy-acme-validation-plugin/blob/master/acme-http01-webroot.lua](link url).

      Unfortunately, the acme plugin doesn't seem to be able to write the token file. I've checked the logs, both general and the acme log mentioned below, but nothing shows up. The directory in question exists as shown below. I've been scratching my head for a couple hours trying to solve this, with no luck. Any help would be appreciated

      ls -al /tmp/haproxy_chroot/haproxywebroot/.well-known/acme-challenge/
      total 8
      drwxrw-rw-  2 root  wheel  64 Aug 28 17:25 .
      drwxr-xr-x  3 root  wheel  64 Aug 28 15:52 ..
      -rw-rw-rw-  1 root  wheel  43 Aug 28 17:25 _s1qu-iKQquucEl99yMlOHgdssWW1LklUQe5cYnaDeM
      

      I created the file above just to verify the script can access it. It's a different challenge file.

      Here's the log from the acme client starting on the line it should have written the token file to:

      put token at: /tmp/haproxy_chroot/haproxywebroot/.well-known/acme-challenge/4DTeprjHhqNIE_K8EJncCuoBfaONNJ_Rt1Db_rN5PbM
      [Sun Aug 28 18:01:38 PDT 2022] Pending, The CA is processing your order, please just wait. (1/30)
      [Sun Aug 28 18:01:41 PDT 2022] Found domain http api file: /tmp/acme/[redacted].cx//httpapi/pfSenseacme.sh
      [Sun Aug 28 18:01:41 PDT 2022] [redacted].cx:Verify error:99.78.100.117: Invalid response from http://[redacted].cx/.well-known/acme-challenge/4DTeprjHhqNIE_K8EJncCuoBfaONNJ_Rt1Db_rN5PbM: 404
      [Sun Aug 28 18:01:41 PDT 2022] Please check log file for more details: /tmp/acme/[redacted].cx/acme_issuecert.log
      
      Gertjan 1 Reply Last reply Reply Quote 0
      • Gertjan
        Gertjan @Bill Harris last edited by Gertjan

        @bill-harris

        Place a file like test.html with content "hello" in /tmp/haproxy_chroot/haproxywebroot/.well-known/acme-challenge/
        and in http://[redacted].cx/.well-known/acme-challenge/

        Now, from the outside ( !!! ) check :
        http://[redacted].cx/.well-known/acme-challenge/test.html
        http://[redacted].cx/test.html

        Can you open / see these files ?

        Also, when it says "4DTeprjHhqNIE_K8EJncCuoBfaONNJ_Rt1Db_rN5PbM" created,
        was the file visible in tmp/haproxy_chroot/haproxywebroot/.well-known/acme-challenge/
        use console or SFTP to check.
        Did it contain a token ?

        edit : why would you need a LUA script from an external source to make acme.sh work ?

        No "help me" PM's please. Use the forum.

        B 2 Replies Last reply Reply Quote 0
        • B
          Bill Harris @Gertjan last edited by

          Now, from the outside ( !!! ) check :

          The file is served as expected from an outside connection (phone with wifi disabled)

          Also, when it says "4DTeprjHhqNIE_K8EJncCuoBfaONNJ_Rt1Db_rN5PbM" created,
          was the file visible in tmp/haproxy_chroot/haproxywebroot/.well-known/acme-challenge/

          The file does not exist after the script fails. It's possible the acme script cleans up the file before I could check? I haven't tracked down the script source to troubleshoot there... That's probably the best course of action if all else fails.

          find /  -name "*4DTeprjHhqNIE_K8EJncCuoBfaONNJ_Rt1Db_rN5PbM*"
          returns no results
          

          edit : why would you need a LUA script from an external source to make acme.sh work ?

          I'm using HAProxy with an LUA script backend to serve the request. I've looked it over and it's harmless. It simply verifies the existence of the challenge file that the acme script wrote and returns the contents.

          Is there a better way to serve the file from pfsense directly? I'm trying to avoid additional dependencies for certificate generation/renewal.

          B 1 Reply Last reply Reply Quote 0
          • B
            Bill Harris @Bill Harris last edited by

            @bill-harris said in Problem using webroot local folder - hash file not created:

            The file does not exist after the script fails. It's possible the acme script cleans up the file before I could check? I haven't tracked down the script source to troubleshoot there... That's probably the best course of action if all else fails.

            I tracked down the location of the acme script and it does indeed clean up the token file by the time it's done. After removing that bit of code, I was able to verify that it's properly writing the file in the expected location. My problem is that the LUA script is failing to open the file and thus can't read/serve it from HAProxy. I'll figure it out and post the solution whether it's a filesystem or LUA permission thing.

            1 Reply Last reply Reply Quote 0
            • B
              Bill Harris @Gertjan last edited by

              @gertjan Looks like lua under haproxy is forbidden from doing file io because it blocks.. Time to figure out how to configure the local pfsense nginx process to serve the file.

              1 Reply Last reply Reply Quote 0
              • S
                Soyokaze last edited by

                FYI just today that script gave me hassles until it... just started to work.

                Same script by Jan Broer as always, same config as always.

                pfsense: 2.6.0-RELEASE (amd64)
                acme: 0.7.3
                haproxy: 0.61_7
                

                Frontend configuration:

                ACL configuration

                ACL Name: url_acme_http01
                Expression: "Path starts with:"
                Value: /.well-known/acme-challenge/
                

                Actions

                Action: http-request lua service
                Condition acl names: METH_GET url_acme_http01
                lua-function: acme-http01
                

                Lua script in case I lose it again:

                -- ACME http-01 domain validation plugin for Haproxy 1.6+
                -- copyright (C) 2015 Jan Broer
                --
                -- usage:
                --
                -- 1) copy acme-webroot.lua in your haproxy config dir
                -- 
                -- 2) Invoke the plugin by adding in the 'global' section of haproxy.cfg:
                -- 
                --    lua-load /etc/haproxy/acme-webroot.lua
                -- 
                -- 3) insert these two lines in every http frontend that is
                --    serving domains for which you want to create certificates:
                -- 
                --    acl url_acme_http01 path_beg /.well-known/acme-challenge/
                --    http-request use-service lua.acme-http01 if METH_GET url_acme_http01
                --
                -- 4) reload haproxy
                --
                -- 5) create a certificate:
                --
                -- ./letsencrypt-auto certonly --text --webroot --webroot-path /var/tmp -d blah.example.com --renew-by-default --agree-tos --email my@email.com
                --
                
                acme = {}
                acme.version = "0.1.1"
                
                --
                -- Configuration
                --
                -- When HAProxy is *not* configured with the 'chroot' option you must set an absolute path here and pass 
                -- that as 'webroot-path' to the letsencrypt client
                
                acme.conf = {
                	["non_chroot_webroot"] = ""
                }
                
                --
                -- Startup
                --  
                acme.startup = function()
                	core.Info("[acme] http-01 plugin v" .. acme.version);
                end
                
                --
                -- ACME http-01 validation endpoint
                --
                acme.http01 = function(applet)
                	local response = ""
                	local reqPath = applet.path
                	local src = applet.sf:src()
                	local token = reqPath:match( ".+/(.*)$" )
                
                	if token then
                		token = sanitizeToken(token)
                	end
                
                	if (token == nil or token == '') then
                		response = "bad request\n"
                		applet:set_status(400)
                		core.Warning("[acme] malformed request (client-ip: " .. tostring(src) .. ")")
                	else
                		auth = getKeyAuth(token)
                		if (auth:len() >= 1) then
                			response = auth .. "\n"
                			applet:set_status(200)
                			core.Info("[acme] served http-01 token: " .. token .. " (client-ip: " .. tostring(src) .. ")")
                		else
                			response = "resource not found\n"
                			applet:set_status(404)
                			core.Warning("[acme] http-01 token not found: " .. token .. " (client-ip: " .. tostring(src) .. ")")
                		end
                	end
                
                	applet:add_header("Server", "haproxy/acme-http01-authenticator")
                	applet:add_header("Content-Length", string.len(response))
                	applet:add_header("Content-Type", "text/plain")
                	applet:start_response()
                	applet:send(response)
                end
                
                --
                -- strip chars that are not in the URL-safe Base64 alphabet
                -- see https://github.com/letsencrypt/acme-spec/blob/master/draft-barnes-acme.md
                --
                function sanitizeToken(token)
                	_strip="[^%a%d%+%-%_=]"
                	token = token:gsub(_strip,'')
                	return token
                end
                
                --
                -- get key auth from token file
                --
                function getKeyAuth(token)
                        local keyAuth = ""
                        local path = acme.conf.non_chroot_webroot .. "/.well-known/acme-challenge/" .. token
                        local f = io.open(path, "rb")
                        if f ~= nil then
                                keyAuth = f:read("*all")
                                f:close()
                        end
                        return keyAuth
                end
                
                core.register_init(acme.startup)
                core.register_service("acme-http01", "http", acme.http01)
                

                Need full pfSense in a cloud? PM for details!

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post