https-dev / acme-providers

JSON schema for list of public ACME endpoints
2 stars 0 forks source link

Rough draft of ACME discovery document #1

Open mholt opened 3 years ago

mholt commented 3 years ago

The goal of this project is to design a schema for a universally-accepted document that can be used to enumerate certificate sources for subjects to use when they need to obtain certificates.

The ACME protocol (RFC 8555) has the concept of a "directory endpoint" -- a single URL is all that is needed to configure an ACME client. However, there are now several public ACME servers and who-knows-how-many internal/private servers. Further, ACME is not the only way to obtain certificates (though it is certainly the emerging dominant method) - for example, Caddy can obtain certificates via other means.

If a particular ACME CA is down temporarily or long-term, it would be prudent to switch to another CA quickly and automatically to avoid a downtime ripple effect on sites. To do this, an ACME client needs to know which CAs it can choose from. Thus, our idea is to configure ACME clients with a URL to a "directory of directories", or more generally, configure a server with a single URL that describes multiple certificate issuers in any degree of detail that is required.

This URL could be public, or private: it can benefit all users of PKI, or it can be used internally within organizations that manage their own infrastructure. In other words, anyone can create and host their own version of this document, just like how anyone can spin up their own CA server. A client can choose which directory (or directories!) it wants to trust. The vision is to be able to pre-configure any applications that require CA validations with simply a URL to a directory (or perhaps multiple, for redundancy).

We have selected JSON because of its universality in every language and platform, including easy use on web pages.

Here is what I've come up with so far in light collaboration with @rmhrisk, @mmalone, and Carl Tashian (sorry, I don't know the GitHub username, please tag!):

{
    "version": 1,
    "issuers": [
        {
            // this field should always be present so the parser knows which
            // fields to expect; if missing, maybe could default to "rfc8555"
            "protocol": "rfc8555",

            // organization name
            "name": "Let's Encrypt",

            // it's not uncommon for an ACME CA to have multiple endpoints
            "endpoints": [
                {
                    // required
                    "directory": "https://acme-v02.api.letsencrypt.org/directory",

                    // optionally describe what kind of validations/certificates are offered
                    "capabilities": {
                        "dv": true
                    }
                },
                {
                    "directory": "https://acme-staging-v02.api.letsencrypt.org/directory",
                    "capabilities": {
                        "dv": true
                    },

                    // whether the endpoint is a test/staging endpoint
                    "test": true
                }
            ]
        },
        {
            "protocol": "rfc8555",
            "name": "Sectigo",
            "endpoints": [
                {
                    "directory": "https://acme.sectigo.com/v2/DV",
                    "capabilities": {
                        "dv": true
                    },

                    // the certificate to trust when connecting to this endpoint,
                    // especially useful if not already in trust stores; likely to
                    // be different from the root cert used for issuing certificates
                    "trust_cert": "-----BEGIN CERTIFICATE----- ..."
                },
                {
                    "directory": "https://acme.sectigo.com/v2/OV",
                    "capabilities": {
                        "ov": true
                    }
                },
                {
                    "directory": "https://acme.sectigo.com/v2/EV",
                    "capabilities": {
                        "ev": true,
                        "sxg": true
                    }
                }
            ]
        }
    ]
}

This issue is for discussing the design of this document. An actual schema can come once we decide what it will look like; I prefer to work with more concrete examples.

I know we had some good discussion in our email thread -- feel free to bring your ideas from that thread into this issue if you want to preserve them here in public record, I'll leave that up to you. :)

captn3m0 commented 3 years ago
rmhrisk commented 3 years ago

Thanks for posting!

My concern with challenges is that it is already covered by the directory in ACME and a discovery document like this could get out of date very quickly.

I share the concern on trust_cert.

mholt commented 3 years ago

@captn3m0 Welcome!

Providing a list of challenges for each issuer/endpoint? Would result in a quicker selection in cases where the client is configured to allow/disallow specific challenges - you don't have to check capabilities of each.

Maintaining this would be difficult and error-prone. IMO there should only be a singular source of truth. ACME challenges are dependent on and vary with each individual authorization. The ACME directory does not even specify which challenges can be used since it depends on each identifier.

trust_cert: Keeping this updated/accurate might be tricky. I've seen cases where the same server presents 2 different certs - for eg, depending on which region you connect to.

This is really no different than what already has to be done, however, except right now it has to be done manually: configuring an application to trust a specific root when it makes a connection to the ACME server if it's not in your trust store. This would almost never be used with public endpoints since those would likely already be trusted (see e.g. ZeroSSL and Let's Encrypt and BuyPass). So if you have a private CA with multi-region capabilities and it's providing a different root for each region, that seems like a difficult complication that already has to be dealt with, but manually. So I'm not sure, but I think that's an orthogonal issue to a directory.

BenBE commented 3 years ago

You don't have to go as far as multi-region deployments. A simple™ case where the root can easily be different depending on the client are scenarios with different Root CAs depending on the signature used, e.g. RSA roots vs. ECC roots.

mholt commented 3 years ago

Sure, but even then you're still manually configuring your application to support one or the other root when it connects. This is no different except now it's embedded in the document so it can be used to automate the config.