Updating README with enhanced detail on what happens where.

This commit is contained in:
Richard Barnes 2015-05-31 23:35:45 -04:00
parent 791118eee7
commit f0e2d1fa28
2 changed files with 255 additions and 76 deletions

251
DESIGN.md Normal file
View File

@ -0,0 +1,251 @@
# Boulder flow diagrams
Boulder is built in a rather decentralized way in order to enable different
parts to be deployed in different security contexts. (Of course, they can
also be run together, as in `./cmd/boulder`.)
In order to you understand how boulder works and ensure it's working correctly,
this document lays out how various operations flow through boulder. We show a
diagram of how calls go between components, and provide notes on what each
component does to help the process along. Each step is in its own subsection
below, in roughly the order that they happen in certificate issuance.
A couple of notes:
* For simplicity, we do not show interactions with the Storage Authority.
The SA simply acts as a common data store for the various components. It
is written to by the RA (registrations and authorizations) and the CA
(certificates), and read by WFE, RA, and CA.
* The interactions shown in the diagrams are the calls that go between
components. These calls can be done directly (as in `./cmd/boulder`), or
they can be done via the AMQP-based RPC code in `./rpc/`. We do not
distinguish between those cases here.
## New Registration
```
1: Client ---new-reg--> WFE
2: WFE ---NewRegistration--> RA
3: WFE <-------return------- RA
4: Client <------------ WFE
```
Notes:
* 1-2: WFE does the following:
* Verify that the request is a POST
* Verify the JWS signature on the POST body
* Parse the registration object
* Filters illegal fields from the registration object
* 2-3: RA does the following:
* Verify that the registered account key is acceptable
* Create a new registration and add the client's information
* Store the registration (which gives it an ID)
* Return the registration as stored
* 3-4: WFE does the following:
* Return the registration, with a unique URL
## Updated Registration
```
1: Client ---reg--> WFE
2: WFE ---UpdateRegistration--> RA
3: WFE <--------return--------- RA
4: Client <-------- WFE
```
* 1-2: WFE does the following:
* Verify that the request is a POST
* Verify the JWS signature on the POST body
* Verify that the JWS signature is by a registered key
* Verify that the JWS key matches the registration for the URL
* Parse the registration object
* Filter illegal fields from the registration object
* 2-3: RA does the following:
* Merge the update into the existing registration
* Store the updated registration
* Return the updated registration
* 3-4: WFE does the following:
* Return the updated registration
## New Authorization
```
1: Client ---new-authz--> WFE
2: WFE ---NewAuthorization--> RA
3: WFE <-------return-------- RA
4: Client <-------------- WFE
```
* 1-2: WFE does the following:
* Verify that the request is a POST
* Verify the JWS signature on the POST body
* Verify that the JWS signature is by a registered key
* Verify that the client has indicated agreement to terms
* Parse the initial authorization object
* 2-3: RA does the following:
* Verify that the requested identifier is allowed by policy
* Create challenges as required by policy
* Construct URIs for the challenges
* Store the authorization
* 3-4: WFE does the following:
* Return the authorization, with a unique URL
## Challenge Response
```
1: Client ---chal--> WFE
2: WFE ---UpdateAuthorization--> RA
3: RA ---UpdateValidations--> VA
4: RA <-------return--------- VA
5: WFE <--------return---------- RA
6: Client <--------- WFE
7: Client <~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~> VA
8: RA <--OnValidationUpdate-- VA
9: RA --------return--------> VA
```
* 1-2: WFE does the following:
* Look up the referenced authorization object
* Look up the referenced challenge within the authorization object
* Verify that the request is a POST
* Verify the JWS signature on the POST body
* Verify that the JWS signature is by a registered key
* Verify that the JWS key corresponds to the authorization
* Verify that the client has indicated agreement to terms
* Parse the challenge object (i.e., the response)
* 2-3: RA does the following:
* Merge the response with the challenge in the authorzation object
* Store the updated authorization object
* 3-4: VA does the following:
* Dispatch a goroutine to do validation
* 4-5: RA does the following:
* Return the updated authorization object
* 5-6: WFE does the following:
* Return the updated authorization object
* 7: VA does the following:
* Validate domain control according to the challenge responded to
* Notify the RA of the result
* 8-9: RA does the following:
* Check that a sufficient set of challenges has been validated
* Mark the authorization as valid or invalid
* Store the updated authorization object
## Authorization Poll
```
1: Client ---authz--> WFE
2: Client <---------- WFE
```
* 1-2: WFE does the following:
* Look up the referenced authorization
* Verify that the request is a GET
* Return the authorization object
## New Certificate
```
1: Client ---new-cert--> WFE
2: WFE ---NewCertificate--> RA
3: RA ---IssueCertificate--> CA
4: CA --> CFSSL
5: CA <-- CFSSL
6: RA <------return--------- CA
7: WFE <------return------- RA
8: Client <------------- WFE
```
* 1-2: WFE does the following:
* Verify that the request is a POST
* Verify the JWS signature on the POST body
* Verify that the JWS signature is by a registered key
* Verify that the client has indicated agreement to terms
* Parse the certificate request object
* 2-3: RA does the following:
* Verify the PKCS#10 CSR in the certificate request object
* Verify that the CSR has a non-zero number of domain names
* Verify that the combination of domain names has not been previously denied
* Verify that the public key in the CSR is different from the account key
* For each authorization referenced in the certificate request
* Retreive the authorization from the database
* Verify that the authorization corresponds to the account key
* Verify that the authorization is valid
* Verify that the authorization is still valid
* Verify that all domains in the CSR are covered by authorizations
* Compute the earliest expiration date among the authorizations
* 3-4: CA does the following:
* Verify that the public key in the CSR meets quality requirements
* RSA only for the moment
* Modulus >= 2048 bits and not divisible by small primes
* Exponent > 2^16
* Remove any duplicate names in the CSR
* Verify that all names are allowed by policy (also checked at new-authz time)
* Verify that the issued cert will not be valid longer than the CA cert
* Verify that the issued cert will not be valid longer than the underlying authorizations
* Open a CA DB transaction and allocate a new serial number
* Request that CFSSL sign the certificate
* 5-6: CA does the following:
* Store the certificate
* Commit the CA DB transaction if everything worked
* ... otherwise return the serial number
* 6-7: RA does the following:
* Log the success or failure of the request
* Return the certificate object
* 7-8: WFE does the following:
* Create a URL from the certificate's serial number
* Return the certificate with it's URL
## Revoke Certificate
```
1: Client ---cert--> WFE
2: WFE ---NewCertificate--> RA
3: RA ---IssueCertificate--> CA
4: RA <------return--------- CA
5: WFE <------return------- RA
6: Client <--------- WFE
```
* 1-2: WFE does the following:
* Verify that the request is a POST
* Verify the JWS signature on the POST body
* Verify that the JWS signature is either:
* The account key for the certificate, or
* The public key from the certificate
* Parse the certificate request object
* 3-4: CA does the following:
* Sign an OCSP response indicating revoked status for this certificate
* Store the OCSP response in the database
* 4-5: RA does the following:
* Log the success or failure of the revocation
* 5-6: WFE does the following:
* Return an indication of the sucess or failure of the revocation

View File

@ -78,28 +78,17 @@ In Boulder, these components are represented by Go interfaces. This allows us t
Internally, the logic of the system is based around two types of objects, authorizations and certificates, mapping directly to the resources of the same name in ACME.
Requests from ACME clients result in new objects and changes objects. The Storage Authority maintains persistent copies of the current set of objects.
Requests from ACME clients result in new objects and changes to objects. The Storage Authority maintains persistent copies of the current set of objects.
Objects are also passed from one component to another on change events. For example, when a client provides a successful response to a validation challenge, it results in a change to the corresponding validation object. The Validation Authority forward the new validation object to the Storage Authority for storage, and to the Registration Authority for any updates to a related Authorization object.
Boulder supports distributed operation using AMQP as a message bus (e.g., via RabbitMQ). For components that you want to be remote, it is necessary to instantiate a "client" and "server" for that component. The client implements the component's Go interface, while the server has the actual logic for the component. More details in `amqp-rpc.go`.
Files
-----
The full details of how the various ACME operations happen in Boulder are laid out in [DESIGN.md](https://github.com/letsencrypt/boulder/blob/master/DESIGN.md)
* `interfaces.go` - Interfaces to the components, implemented in:
* `web-front-end.go`
* `registration-authority.go`
* `validation-authority.go`
* `certificate-authority.go`
* `storage-authority.go`
* `amqp-rpc.go` - A lightweight RPC framework overlaid on AMQP
* `rpc-wrappers.go` - RPC wrappers for the various component type
* `objects.go` - Objects that are passed between components
* `util.go` - Miscellaneous utility methods
* `boulder_test.go` - Unit tests
Dependencies:
Dependencies
------------
All dependencies are vendorized under the Godeps directory,
both to [make dependency management
@ -124,67 +113,6 @@ git commit
sudo iptables -D OUTPUT 1
```
ACME Processing
---------------
```
Client -> WebFE: challengeRequest
WebFE -> RA: NewAuthorization(AuthorizationRequest)
RA -> RA: [ select challenges ]
RA -> RA: [ create Validations with challenges ]
RA -> RA: [ create Authorization with Validations ]
RA -> SA: Update(Authorization.ID, Authorization)
RA -> WebFE: Authorization
WebFE -> WebFE: [ create challenge from Authorization ]
WebFE -> WebFE: [ generate nonce and add ]
WebFE -> Client: challenge
----------
Client -> WebFE: authorizationRequest
WebFE -> WebFE: [ look up authorization based on nonce ]
WebFE -> WebFE: [ verify authorization signature ]
WebFE -> RA: UpdateAuthorization(Authorization)
RA -> RA: [ add responses to authorization ]
RA -> SA: Update(Authorization.ID, Authorization)
RA -> VA: UpdateValidations(Authorization)
WebFE -> Client: defer(authorizationID)
VA -> SA: Update(Authorization.ID, Authorization)
VA -> RA: OnValidationUpdate(Authorization)
RA -> RA: [ check that validation sufficient ]
RA -> RA: [ finalize authorization ]
RA -> SA: Update(Authorization.ID, Authorization)
RA -> WebFE: OnAuthorizationUpdate(Authorization)
Client -> WebFE: statusRequest
WebFE -> Client: error / authorization
----------
Client -> WebFE: certificateRequest
WebFE -> WebFE: [ verify authorization signature ]
WebFE -> RA: NewCertificate(CertificateRequest)
RA -> RA: [ verify CSR signature ]
RA -> RA: [ verify authorization to issue ]
RA -> RA: [ select CA based on issuer ]
RA -> CA: IssueCertificate(CertificateRequest)
CA -> RA: Certificate
RA -> CA: [ look up ancillary data ]
RA -> WebFE: AcmeCertificate
WebFE -> Client: certificate
----------
Client -> WebFE: revocationRequest
WebFE -> WebFE: [ verify authorization signature ]
WebFE -> RA: RevokeCertificate(RevocationRequest)
RA -> RA: [ verify authorization ]
RA -> CA: RevokeCertificate(Certificate)
CA -> RA: RevocationResult
RA -> WebFE: RevocationResult
WebFE -> Client: revocation
```
TODO
----