unixcharles / acme-client

A Ruby client for the letsencrypt's ACME protocol.
MIT License
495 stars 116 forks source link

Multiple domains or wildcard #146

Closed tonymadbrain closed 4 years ago

tonymadbrain commented 6 years ago

Can't find how to deal with multiple domains in one certificate and wildcard certificates. Can you please describe steps with little code examples?

gmarco commented 6 years ago

order must contain all reqest domain order = client.new_order(identifiers: ['domain1.de','*.domain1.de']) order.authorizations.each do |authorization| # loop over all auth's

csr with: csr = Acme::Client::CertificateRequest.new(private_key: a_different_private_key, subject: { common_name: 'domain1.de' } ,names: ["domain1.de","*.domain1.de"] )

this works so for, but the example with :

while challenge.status == 'pending' 
  sleep(5)
  challenge.reload
end

will never get over "pending", waiting for multiple minutes, an run again, shows that auth was done, but the reload never showed that. what is the problem here ?

unixcharles commented 6 years ago

Did you complete the required challenges?

gmarco commented 6 years ago

after many tries: yes.

the main thing was: add DNS entry and wait for Entry to be seen in public server, then request the auth. After that the status goes to valid. If you put the DNS record and try to validate this (also with while loop after that) it will never get valid.

weppos commented 6 years ago

You explicitly need to request a validation from the CA. The CA will not attempt to perform any challenge validation until you are ready and you tell them to do so.

You are missing:

challenge.request_validation

The steps are:

  1. obtain the authorization and the challenge
  2. provision the challenge (e.g. the DNS record) and test it actually works as expected
  3. request the validation

Note that the validation is final. If the validation doesn't succeed (e.g. because the DNS record doesn't resolve) the status will go to invalid and you won't be able to request a new validation without re-starting a new order and a new challenge.

unixcharles commented 6 years ago

I didn't had too much time lately but I'll add instruction for wildcard whenever I have time.

To be honest, I've never tried this specific flow myself. I just implemented the spec and assumed it would work. I have had confirmation from pretty heavy users of the gem that it works.

richardonrails commented 6 years ago

It works. I have something like this...

Example: domains = ['example.com', '*.example.com', 'foo.example.net']

  def generate_cert(client, domains)
    order = client.new_order(identifiers: domains)
    authorizations = order.authorizations

    authorizations.each do |authorization|
      domain = authorization.domain

      if authorization.status == 'pending'

        if authorization.wildcard
          challenge = authorization.dns
          update_dns_record(domain, challenge.record_name, challenge.record_content)

          # You only get one shot for the DNS challenge. If you try to validate/verify
          # the challenge immediately it sees the old DNS record content and challenge 
          # status is 'invalid' you can't try again. So we just sleep long enough so that it works...
          sleep(10)
        else
          challenge = authorization.http
          create_file(challenge.filename, challenge.file_content)
        end

        challenge.request_validation

        while challenge.status == 'pending'
          sleep(0.25)
          challenge.reload
        end

        puts challenge.error unless challenge.status == 'valid'
      end
    end

    csr = Acme::Client::CertificateRequest.new(
      common_name: domains[0],
      names: domains
    )
    order.finalize(csr: csr)

    sleep(1) while order.status == 'processing'

    certificate = order.certificate

    return certificate, csr
  end
mcr commented 5 years ago

Why would you attempt to validate the challenges one at a time? Wouldn't it be better to do all the file creations and DNS updates first, and then validate them all?

weppos commented 5 years ago

Why would you attempt to validate the challenges one at a time? Wouldn't it be better to do all the file creations and DNS updates first, and then validate them all?

You can't. Each challenge contains an unique token that is provided by Let's Encrypt that you must expose (e.g. via DNS) to prove the match with the challenge.

mcr commented 5 years ago

Simone Carletti notifications@github.com wrote:

Why would you attempt to validate the challenges one at a time? Wouldn't it be better to do all the file creations and DNS updates first, and then validate them all?

You can't. Each challenge contains an unique token that is provided by Let's Encrypt that you must expose (e.g. via DNS) to prove the match with the challenge.

They go into different DNS names.

-- ] Never tell me the odds! | ipv6 mesh networks [ ] Michael Richardson, Sandelman Software Works | IoT architect [ ] mcr@sandelman.ca http://www.sandelman.ca/ | ruby on rails [