auto-ssl / lua-resty-auto-ssl

On the fly (and free) SSL registration and renewal inside OpenResty/nginx with Let's Encrypt.
MIT License
1.93k stars 182 forks source link

Can't issue an ssl certificate for domains proxied by Cloudflare #258

Open justemma opened 3 years ago

justemma commented 3 years ago

Hello!

I was playing around with lua-resty-auto-ssl and everything worked perfectly until I tried issuing a certificate for a domain proxied by Cloudflare (orange cloud).

This is/are the error/s that I'm getting for the domain that is proxied:

2021/05/27 22:49:03 [error] 102203#102203: *20 [lua] ssl_certificate.lua:68: issue_cert(): auto-ssl: failed to obtain lock: timeout, context: ssl_certificate_by_lua*, client: 162.158.62.86, server: 0.0.0.0:443
2021/05/27 22:49:03 [error] 102203#102203: *20 [lua] ssl_certificate.lua:291: auto-ssl: could not get certificate for xyz.example.com - using fallback - failed to get or issue certificate, context: ssl_certificate_by_>
2021/05/27 22:49:03 [error] 102203#102203: *19 open() "/usr/local/openresty/nginx/html/.well-known/acme-challenge/dImjROwMMdY-dfPkAE-edit" failed (2: No such file or directory), client: 162.158.62.86, serv>
2021/05/27 22:49:03 [error] 102203#102203: *5 [lua] lets_encrypt.lua:40: issue_cert(): auto-ssl: dehydrated failed: env HOOK_SECRET=edited HOOK_SERVER_PORT=8999 /usr/l>
startup_hook
Processing xyz.example.com
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting new certificate order from CA...
 + Received 1 authorizations URLs from the CA
 + Handling authorization for xyz.example.com
 + 1 pending challenge(s)
 + Deploying challenge tokens...
deploy_challenge
 + Responding to challenge for xyz.example.com authorization...
invalid_challenge
Invalid challenge: DOMAIN=xyz.example.com RESPONSE={
  "type": "http-01",
  "status": "invalid",
  "error": {
    "type": "urn:ietf:params:acme:error:unauthorized",
    "detail": "Invalid response from https://xyz.example.com/.well-known/acme-challenge/dImjROwMMdY-dfPkAE-edit [2606:4700:3035::ac43:8192]: \"\u003chtml\u003e\\r\\n\u003chead\u003e\u003ctitle\u003>    
     "status": 403
  },
  "url": "https://acme-v02.api.letsencrypt.org/acme/chall-v3/13492436985/xRMMmQ",
  "token": "dImjROwMMdY-dfPkAE-edit",
  "validationRecord": [
    {
      "url": "http://xyz.example.com/.well-known/acme-challenge/dImjROwMMdY-dfPkAE-edit",
      "hostname": "xyz.example.com",
      "port": "80",
      "addressesResolved": [
        "104.21.2.190",
        "172.67.129.146",
        "2606:4700:3035::ac43:8192",
        "2606:4700:3036::6815:2be"
      ],
      "addressUsed": "2606:4700:3035::ac43:8192"
    },
    {
      "url": "https://xyz.example.com/.well-known/acme-challenge/dImjROwMMdY-dfPkAE-edit",
      "hostname": "xyz.example.com",
      "port": "443",
      "addressesResolved": [
        "172.67.129.146",
        "104.21.2.190",
        "2606:4700:3035::ac43:8192",
        "2606:4700:3036::6815:2be"
      ],
      "addressUsed": "2606:4700:3035::ac43:8192"
    }
  ],
  "validated": "2021-05-27T22:48:32Z"
}
 err: nil, context: ssl_certificate_by_lua*, client: 162.158.63.246, server: 0.0.0.0:443
2021/05/27 22:49:03 [error] 102203#102203: *5 [lua] ssl_certificate.lua:97: issue_cert(): auto-ssl: issuing new certificate failed: dehydrated failure, context: ssl_certificate_by_lua*, client: 162.158.63.246, server: 0.0.0.0>
2021/05/27 22:49:03 [error] 102203#102203: *5 [lua] ssl_certificate.lua:53: issue_cert_unlock(): auto-ssl: failed to unlock: lock does not match expected value, context: ssl_certificate_by_lua*, client: 162.158.63.246, server>
2021/05/27 22:49:03 [error] 102203#102203: *5 [lua] ssl_certificate.lua:291: auto-ssl: could not get certificate for xyz.example.com - using fallback - failed to get or issue certificate, context: ssl_certificate_by_l> 

Here is my nginx.conf (pretty much the default one but I'm using redis to store the ssl certificates):

user root;

events {
  worker_connections 1024;
}

http {
  access_log /var/log/openresty/access.log;
  error_log /var/log/openresty/error.log;

  lua_shared_dict auto_ssl 10m;
  lua_shared_dict auto_ssl_settings 64k;
  resolver 8.8.8.8 ipv6=off;

  init_by_lua_block {
    auto_ssl = (require "resty.auto-ssl").new()

    auto_ssl:set("renew_check_interval", 86400)
    auto_ssl:set("storage_adapter", "resty.auto-ssl.storage_adapters.redis")
    auto_ssl:set("redis", {
      host = "x.x.x.x",
      auth = "password",
      port = "6379",
      prefix = "ssl"
    })

    auto_ssl:set("allow_domain", function(domain, auto_ssl, ssl_options, renewal)
      return true
    end)
    auto_ssl:init()
  }

  init_worker_by_lua_block {
    auto_ssl:init_worker()
  }

  server {
    listen 443 ssl;

    ssl_certificate_by_lua_block {
      auto_ssl:ssl_certificate()
    }

    ssl_certificate /etc/ssl/resty-auto-ssl-fallback.crt;
    ssl_certificate_key /etc/ssl/resty-auto-ssl-fallback.key;
  }

  server {
    listen 80;

    location /.well-known/acme-challenge/ {
      content_by_lua_block {
        auto_ssl:challenge_server()
      }
    }
  }

  server {
    listen 127.0.0.1:8999;

    client_body_buffer_size 128k;
    client_max_body_size 128k;

    location / {
      content_by_lua_block {
        auto_ssl:hook_server()
      }
    }
  }
}

After trying once to issue the ssl certificate for the proxied domain this is what I have in redis:

1) "ssl:xyz.example.com:challenge:lZsCo9o6iNsNKnTPNGjnUavffxTBI0I-cdwfef"
2) "ssl:xyz.example.com:challenge:XfxXtUQ9y08GIrO8Il3MY5_t94ZOxduYHRg"
3) "ssl:xyz.example.com:challenge:xe9E_szfJ_xcRD70d3uGJGaur5QFH-6co-FLtaGdY"
4) "ssl:xyz.example.com:challenge:BQaUHoAHk1NiauSJNvLmRPSd5eS1FoyK9WEsa1Vp9NA"
5) "ssl:xyz.example.com:challenge:dImjRzwMtdY-ddo2ix-yx8izv_qP_o-cu5KxACveqQo"

And...again, if I use DNS only instead of Proxied the ssl certificate is issued without a problem.

Can somebody help me understand what's happening? Is there something that I can change/implement in order to allow both proxied/dns only domains to get their own ssl certificate?

Thank you! :D

gjongenelen commented 3 years ago

If your site is behind CloudFlare proxy, the best option is to not use Let’s Encrypt at all, but instead to use Cloudflare’s Origin CA: https://blog.cloudflare.com/cloudflare-ca-encryption-origin/

justemma commented 3 years ago

@gjongenelen I failed to mention that I'm trying to generate certificates for multiple domains and just some of them are on Cloudflare. I apologize for that :( .

Is there a way to generate a certificate for both, proxied and not proxied domains (through Crowdrole or any other dns console/proxy provider) ?

gjongenelen commented 3 years ago

Do you have "Always SSL/HTTPS" option enabled in Cloudflare. Depending on your config, this may create issues as cloudflare will forward acme challenges to your HTTPS handler.

justemma commented 3 years ago

Oh, turning "Always SSL/HTTPS" off fixed it! Can you give me more info regarding the last part of your answer: "Depending on your config, this may create issues as cloudflare will forward acme challenges to your HTTPS handler" - how can it be configured in a way that would allow me to use "Always SSL/HTTPS"?

Thanky you! :D

gjongenelen commented 3 years ago

You probably have:

location /.well-known/acme-challenge/ {
      content_by_lua_block {
        auto_ssl:challenge_server()
      }
    }

in your http (tcp/80) handler. I think copying this block to your https-handler would fix the issue. Please copy/duplicate and don't remove it from the http-handler, as let's encrypt will still use the http-handler for domains which aren't proxied via cloudflare.

justemma commented 3 years ago

Hey @gjongenelen , thank you so much for helping me (and hopefully others) but unfortunatelly that one didn't work (copy/paste the acme challenge location block from port 80 to 443) , i still can't issue certificates for domains that have "Always use https" enabled on cloudflare. Any other ideas? Thank you! 😄

whizzygeeks commented 2 years ago

You probably have:

location /.well-known/acme-challenge/ {
      content_by_lua_block {
        auto_ssl:challenge_server()
      }
    }

in your http (tcp/80) handler. I think copying this block to your https-handler would fix the issue. Please copy/duplicate and don't remove it from the http-handler, as let's encrypt will still use the http-handler for domains which aren't proxied via cloudflare.

This will probably wont work, letsencrypt always connects on http for challenge url. Best way i see it is to introduce dns validation and skip certificate generation for those domains that do not have correct entries. lua-resty-dns module can be used

gjongenelen commented 2 years ago

This will probably wont work, letsencrypt always connects on http for challenge url. Best way i see it is to introduce dns validation and skip certificate generation for those domains that do not have correct entries. lua-resty-dns module can be used

My guess was that the "Always SSL/HTTPS" setting was redirecting the challenges to the https-handler. DNS validation would be a better option indeed.

arturmkrtchyan commented 2 years ago

Any idea how one could do on-the-fly DNS validations and not try to generate certificates for those proxied calls ? Would it be adding custom code in allow_domain function ?

benjamindell commented 1 year ago

Sorry to hijack the post, but we're facing a similar issue. We've just moved over from Route53 to CloudFlare and have now turned on DNS proxy. With proxy turned on we get a similar "ERR_SSL_VERSION_OR_CIPHER_MISMATCH" error for custom domains that we pass via our openresty auto SSL EC2 server to have the SSL certificate created.

I've tried turning off the "Always SSL/HTTPS" setting but that didn't seem to make a difference.

We are also doing a DNS lookup in our lua script, so I'm not sure if that makes a difference.

I don't suppose anyone has any suggestions for other things we might want to check?

whizzygeeks commented 1 year ago

Hi Benjamin ,

Cloudflare also uses Letsencrypt to issue the certificates. So in case if you have already issued a certificate using letsencrypt , there is a high probability of cloudflare not issuing the certificate for same domain .

Few options :

Let know if you require technical support for it

Thanks & Regards, Abhishek Sharma

On Fri, 27 Jan 2023, 8:16 pm Benjamin Dell, @.***> wrote:

Sorry to hijack the post, but we're facing a similar issue. We've just moved over from Route53 to CloudFlare and have now turned on DNS proxy. With proxy turned on we get a similar "ERR_SSL_VERSION_OR_CIPHER_MISMATCH" error for custom domains that we pass via our openresty auto SSL EC2 server to have the SSL certificate created.

I've tried turning off the "Always SSL/HTTPS" setting but that didn't seem to make a difference.

We are also doing a DNS lookup in our lua script, so I'm not sure if that makes a difference.

I don't suppose anyone has any suggestions for other things we might want to check?

— Reply to this email directly, view it on GitHub https://github.com/auto-ssl/lua-resty-auto-ssl/issues/258#issuecomment-1406603058, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHU3WWMXLW5A3BIUHBSU3ZTWUPNTTANCNFSM45VJ6NAA . You are receiving this because you commented.Message ID: @.***>

benjamindell commented 1 year ago

Amazing, thanks Abhishek. Just wanted to clarify a couple of things if that's OK.

I don't think we actually created a cert and pen on our EC2 SSL server (the one that uses auto SSL to generate SSL certs for our customers custom domains). Or will there be one on the server that im not aware of?

I'd be interested in some technical help if that's OK? Is that something I can pay you for perhaps?

whizzygeeks commented 1 year ago

Autossl generates a certificate and keeps it on a local server. Location is dependent on configuration. For default file storage you can find in some subidrectory of /etc/resty-auto-ssl location. You can run locate or find command to search the certificate I need to understand and evaluate the requirements based on the platform. We can start a new communication thread in case you require support, please DM me directly

benjamindell commented 1 year ago

Thanks - I've just sent you an email to see if you're able to help directly.