249 lines
7.6 KiB
Go
249 lines
7.6 KiB
Go
// Copyright 2014 ISRG. All rights reserved
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/codegangsta/cli"
|
|
"github.com/letsencrypt/boulder"
|
|
"github.com/streadway/amqp"
|
|
"net/http"
|
|
"os"
|
|
)
|
|
|
|
// Exit and print error message if we encountered a problem
|
|
func failOnError(err error, msg string) {
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "%s: %s\n", msg, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
// This is the same as amqpConnect in boulder, but with even
|
|
// more aggressive error dropping
|
|
func amqpChannel(url string) (ch *amqp.Channel) {
|
|
conn, err := amqp.Dial(url)
|
|
failOnError(err, "Unable to connect to AMQP server")
|
|
|
|
ch, err = conn.Channel()
|
|
failOnError(err, "Unable to establish channel to AMQP server")
|
|
return
|
|
}
|
|
|
|
// Start the server and wait around
|
|
func runForever(server *boulder.AmqpRpcServer) {
|
|
forever := make(chan bool)
|
|
server.Start()
|
|
fmt.Fprintf(os.Stderr, "Server running...\n")
|
|
<-forever
|
|
}
|
|
|
|
func main() {
|
|
app := cli.NewApp()
|
|
app.Name = "boulder-start"
|
|
app.Usage = "Command-line utility to start Boulder's servers in stand-alone mode"
|
|
app.Version = "0.0.0"
|
|
|
|
// Server URL hard-coded for now
|
|
amqpServerURL := "amqp://guest:guest@localhost:5672"
|
|
|
|
// One command per element of the system
|
|
// * WebFrontEnd
|
|
// * RegistrationAuthority
|
|
// * ValidationAuthority
|
|
// * CertificateAuthority
|
|
// * StorageAuthority
|
|
//
|
|
// Once started, we just run until killed
|
|
//
|
|
// AMQP queue names are hard-coded for now
|
|
app.Commands = []cli.Command{
|
|
{
|
|
Name: "monolithic",
|
|
Usage: "Start the CA in monolithic mode, without using AMQP",
|
|
Action: func(c *cli.Context) {
|
|
// Create the components
|
|
wfe := boulder.NewWebFrontEndImpl()
|
|
sa := boulder.NewSimpleStorageAuthorityImpl()
|
|
ra := boulder.NewRegistrationAuthorityImpl()
|
|
va := boulder.NewValidationAuthorityImpl()
|
|
ca, err := boulder.NewCertificateAuthorityImpl()
|
|
failOnError(err, "Unable to create CA")
|
|
|
|
// Wire them up
|
|
wfe.RA = &ra
|
|
wfe.SA = &sa
|
|
ra.CA = &ca
|
|
ra.SA = &sa
|
|
ra.VA = &va
|
|
va.RA = &ra
|
|
|
|
// Go!
|
|
authority := "localhost:4000"
|
|
authzPath := "/acme/authz/"
|
|
certPath := "/acme/cert/"
|
|
wfe.SetAuthzBase("http://" + authority + authzPath)
|
|
wfe.SetCertBase("http://" + authority + certPath)
|
|
http.HandleFunc("/acme/new-authz", wfe.NewAuthz)
|
|
http.HandleFunc("/acme/new-cert", wfe.NewCert)
|
|
http.HandleFunc("/acme/authz/", wfe.Authz)
|
|
http.HandleFunc("/acme/cert/", wfe.Cert)
|
|
|
|
fmt.Fprintf(os.Stderr, "Server running...\n")
|
|
err = http.ListenAndServe(authority, nil)
|
|
failOnError(err, "Error starting HTTP server")
|
|
},
|
|
},
|
|
{
|
|
Name: "monolithic-amqp",
|
|
Usage: "Start the CA in monolithic mode, using AMQP",
|
|
Action: func(c *cli.Context) {
|
|
// Create an AMQP channel
|
|
ch := amqpChannel(amqpServerURL)
|
|
|
|
// Create AMQP-RPC clients for CA, VA, RA, SA
|
|
cac, err := boulder.NewCertificateAuthorityClient("CA.client", "CA.server", ch)
|
|
failOnError(err, "Failed to create CA client")
|
|
vac, err := boulder.NewValidationAuthorityClient("VA.client", "VA.server", ch)
|
|
failOnError(err, "Failed to create VA client")
|
|
rac, err := boulder.NewRegistrationAuthorityClient("RA.client", "RA.server", ch)
|
|
failOnError(err, "Failed to create RA client")
|
|
sac, err := boulder.NewStorageAuthorityClient("SA.client", "SA.server", ch)
|
|
failOnError(err, "Failed to create SA client")
|
|
|
|
// ... and corresponding servers
|
|
// (We need this order so that we can give the servers
|
|
// references to the clients)
|
|
cas, err := boulder.NewCertificateAuthorityServer("CA.server", ch)
|
|
failOnError(err, "Failed to create CA server")
|
|
vas, err := boulder.NewValidationAuthorityServer("VA.server", ch, &rac)
|
|
failOnError(err, "Failed to create VA server")
|
|
ras, err := boulder.NewRegistrationAuthorityServer("RA.server", ch, &vac, &cac, &sac)
|
|
failOnError(err, "Failed to create RA server")
|
|
sas := boulder.NewStorageAuthorityServer("SA.server", ch)
|
|
|
|
// Start the servers
|
|
cas.Start()
|
|
vas.Start()
|
|
ras.Start()
|
|
sas.Start()
|
|
|
|
// Wire up the front end (wrappers are already wired)
|
|
wfe := boulder.NewWebFrontEndImpl()
|
|
wfe.RA = &rac
|
|
wfe.SA = &sac
|
|
|
|
// Go!
|
|
authority := "localhost:4000"
|
|
authzPath := "/acme/authz/"
|
|
certPath := "/acme/cert/"
|
|
wfe.SetAuthzBase("http://" + authority + authzPath)
|
|
wfe.SetCertBase("http://" + authority + certPath)
|
|
http.HandleFunc("/acme/new-authz", wfe.NewAuthz)
|
|
http.HandleFunc("/acme/new-cert", wfe.NewCert)
|
|
http.HandleFunc("/acme/authz/", wfe.Authz)
|
|
http.HandleFunc("/acme/cert/", wfe.Cert)
|
|
|
|
fmt.Fprintf(os.Stderr, "Server running...\n")
|
|
err = http.ListenAndServe(authority, nil)
|
|
failOnError(err, "Error starting HTTP server")
|
|
},
|
|
},
|
|
{
|
|
Name: "wfe",
|
|
Usage: "Start the WebFrontEnd",
|
|
Action: func(c *cli.Context) {
|
|
// Create necessary clients
|
|
ch := amqpChannel(amqpServerURL)
|
|
|
|
rac, err := boulder.NewRegistrationAuthorityClient("RA.client", "RA.server", ch)
|
|
failOnError(err, "Unable to create RA client")
|
|
|
|
sac, err := boulder.NewStorageAuthorityClient("SA.client", "SA.server", ch)
|
|
failOnError(err, "Unable to create SA client")
|
|
|
|
// Create the front-end and wire in its resources
|
|
wfe := boulder.NewWebFrontEndImpl()
|
|
wfe.RA = &rac
|
|
wfe.SA = &sac
|
|
|
|
// Connect the front end to HTTP
|
|
authority := "localhost:4000"
|
|
authzPath := "/acme/authz/"
|
|
certPath := "/acme/cert/"
|
|
wfe.SetAuthzBase("http://" + authority + authzPath)
|
|
wfe.SetCertBase("http://" + authority + certPath)
|
|
http.HandleFunc("/acme/new-authz", wfe.NewAuthz)
|
|
http.HandleFunc("/acme/new-cert", wfe.NewCert)
|
|
http.HandleFunc("/acme/authz/", wfe.Authz)
|
|
http.HandleFunc("/acme/cert/", wfe.Cert)
|
|
|
|
fmt.Fprintf(os.Stderr, "Server running...\n")
|
|
http.ListenAndServe(authority, nil)
|
|
},
|
|
},
|
|
{
|
|
Name: "sa",
|
|
Usage: "Start the CertificateAuthority",
|
|
Action: func(c *cli.Context) {
|
|
ch := amqpChannel(amqpServerURL)
|
|
|
|
cas, err := boulder.NewCertificateAuthorityServer("CA.server", ch)
|
|
failOnError(err, "Unable to create CA server")
|
|
runForever(cas)
|
|
},
|
|
},
|
|
{
|
|
Name: "ca",
|
|
Usage: "Start the StorageAuthority",
|
|
Action: func(c *cli.Context) {
|
|
ch := amqpChannel(amqpServerURL)
|
|
|
|
sas := boulder.NewStorageAuthorityServer("SA.server", ch)
|
|
runForever(sas)
|
|
},
|
|
},
|
|
{
|
|
Name: "va",
|
|
Usage: "Start the ValidationAuthority",
|
|
Action: func(c *cli.Context) {
|
|
ch := amqpChannel(amqpServerURL)
|
|
|
|
rac, err := boulder.NewRegistrationAuthorityClient("RA.client", "RA.server", ch)
|
|
failOnError(err, "Unable to create RA client")
|
|
|
|
vas, err := boulder.NewValidationAuthorityServer("VA.server", ch, &rac)
|
|
failOnError(err, "Unable to create VA server")
|
|
runForever(vas)
|
|
},
|
|
},
|
|
{
|
|
Name: "ra",
|
|
Usage: "Start the RegistrationAuthority",
|
|
Action: func(c *cli.Context) {
|
|
// TODO
|
|
ch := amqpChannel(amqpServerURL)
|
|
|
|
vac, err := boulder.NewValidationAuthorityClient("VA.client", "VA.server", ch)
|
|
failOnError(err, "Unable to create VA client")
|
|
|
|
cac, err := boulder.NewCertificateAuthorityClient("CA.client", "CA.server", ch)
|
|
failOnError(err, "Unable to create CA client")
|
|
|
|
sac, err := boulder.NewStorageAuthorityClient("SA.client", "SA.server", ch)
|
|
failOnError(err, "Unable to create SA client")
|
|
|
|
ras, err := boulder.NewRegistrationAuthorityServer("RA.server", ch, &vac, &cac, &sac)
|
|
failOnError(err, "Unable to create RA server")
|
|
runForever(ras)
|
|
},
|
|
},
|
|
}
|
|
|
|
err := app.Run(os.Args)
|
|
failOnError(err, "Failed to run application")
|
|
}
|