letsencrypt / boulder

An ACME-based certificate authority, written in Go.
Mozilla Public License 2.0
5.22k stars 607 forks source link

Creating an "overarching" configurable ceremony type #5276

Open beautifulentropy opened 3 years ago

beautifulentropy commented 3 years ago

Captured from a conversation that @aarongable and I had:

Create a new ceremony config which acts as a meta-config, saying "process these config files in this order, sending the outputs of this step to the inputs of that step"

A declarative replacement for what currently lives in run.sh and some hard-coded paths in the config files.

As an added feature, the program should be able to output a dot file diagramming the hierarchy

digraph structs {
    node [style=filled shape=note fontname=Arial];
    rankdir=TB;
    splines=ortho;
    pad="0";
    ranksep=".8";
    nodesep=".3";
    concentrate=true;
    {rank = same; dstrootcax3; isrgrootx1; isrgrootx2}
    {rank = same; leax1; leax3; r3; e1;}

    subgraph R {
        dstrootcax3 -> isrgrootx1 -> isrgrootx2 [arrowhead=vee]
        dstrootcax3 [label="DST Root CA X3" fillcolor=orange];
        isrgrootx1 [label="ISRG Root X1" fillcolor=orange];
        isrgrootx2 [label="ISRG Root X2" fillcolor=cadetblue3];
    }
    subgraph IR {
        isrgrootx1 -> leax1 -> ee1 [arrowhead=vee]
        isrgrootx1 -> leax3 -> ee2 [arrowhead=vee]
        isrgrootx1 -> r3 -> ee3 [arrowhead=vee]
        dstrootcax3 -> leax1 [color=gray40 style=dotted arrowhead=vee]
        dstrootcax3 -> leax3 [color=gray40 style=dotted arrowhead=vee]
        dstrootcax3 -> r3 [color=gray40 style=dotted arrowhead=vee]
        leax1 [label="LEA X1" fillcolor=orange];
        leax3 [label="LEA X3" fillcolor=orange];
        r3 [label="R3" fillcolor=orange];
        ee1 [label="EE"];
        ee2 [label="EE"];
        ee3 [label="EE"];
    }
    subgraph IE {
        isrgrootx2 -> e1 -> ee4 [arrowhead=vee]
        e1 [label="E1" fillcolor=cadetblue3];
        ee4 [label="EE"];
    }

image

aarongable commented 3 years ago

I'm envisioning that the config for this new ceremony type would look something like:

ceremony-type: meta
step: root-x1
  config: root-x1.yaml
step: int-r3-key
  config: int-r3-key.yaml
step: int-r3-cert
  config: int-r3-cert.yaml
  input:
    issuer: root-x1
    issuee: int-r3-key
step: int-r3-cross-csr
  config: int-r3-cross-csr.yaml
  input:
    issuer: int-r3-key
    issuee: int-r3-key

Each ceremony type has certain kinds of outputs that it produces: private keys in slots on the HSM, and public keys, certificates, CSRs, and CRLs in files on disk. The outputs for each type are non-negotiable, and will always be generated using slot- or file-names given by the name of the step.

Each ceremony type has certain kinds of inputs that it requires. These are usually: a) the issuer key, in the form of an HSM slot and label; b) the issuer certificate, in the form of a file on disk; and c) the key to be signed over, in the form of a public key file on disk.

The meta ceremony will keep track of which outputs are produced by each step. Then when a later step references an earlier step as its input, it will examine the later step to determine which kinds of inputs it needs, and grab the appropriate outputs from the referenced step. It's not yet clear to me whether the meta-ceremony would do all of this by loading the configs into memory and then modifying them on the fly, or by rewriting configs on disk.

In addition, the meta-ceremony may do things like a) create slots on the HSM, and store those slot numbers for use with each individual step b) validate signatures after issuance steps Or maybe these should be done by a new "init-slot" ceremony type and each of the individual issuance ceremony types, respectively.

Anyway, all of this is just a design sketch, that we should refine when we get to the point of actually wanting to do this.

jsha commented 3 years ago

The meta ceremony will keep track of which outputs are produced by each step. Then when a later step references an earlier step as its input, it will examine the later step to determine which kinds of inputs it needs, and grab the appropriate outputs from the referenced step.

Another approach would be for the inputs and outputs to be written in the configs as they are today, but for the meta-ceremony tool to verify that each stage has the inputs it needs, either provided as top-level external inputs, or as outputs of a previous stage.

aarongable commented 3 years ago

I like the idea of having steps reference other steps, rather than referencing specific files output by those steps, because it reduces the number of opportunities for typos and it converts the whole ceremony into something that is much more obviously a dependency graph. But yeah, maybe each individual ceremony config says which other steps it depends on, and the meta ceremony is just a list of files to process and it double-checks that all the dependencies are satisfied before processing anything.

aarongable commented 3 years ago

Rehydrating this bug.

I think that the first version of this can be very simple: "run these ceremony commands with these config files in this order". That's really all we need in order to a) Greatly simplify ceremony scripts; and b) Do overarching checks like "do any of the generated certs have IssuerNameIDs that collide?"

Future improvements like output-to-input chaining are awesome but not necessary for v1 of the meta ceremony type.