unixcharles / acme-client

A Ruby client for the letsencrypt's ACME protocol.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Multiple domains or wildcard

tonymadbrain opened this issue · comments

commented

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

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 ?

Did you complete the required challenges?

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.

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.

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.

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

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?

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.