This repository has been archived by the owner on Apr 20, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gravel.go
218 lines (175 loc) · 5.83 KB
/
gravel.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// +build !windows
package gravel
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"net"
"net/http"
"testing"
"time"
"github.com/18f/gravel/ca"
"github.com/18f/gravel/db"
"github.com/18f/gravel/dns"
"github.com/18f/gravel/va"
"github.com/18f/gravel/wfe"
"github.com/18f/gravel/wrappers"
"github.com/sirupsen/logrus"
)
// Integration environment for Let's Encrypt.
type Gravel struct {
// The internal DNS server used for integration and record serving.
DnsServer *dns.IntegrationServer
// Internal certificate database.
Database db.GravelStore
// Verification Authority implementation.
VerificationAuthority *va.VerificationAuthority
// Certificate Authority for a given Gravel instance.
CertificateAuthority *ca.CertificateAuthority
// Web Front End for a given Gravel instance.
WebFrontEnd *wfe.WebFrontEnd
// Internal certificate manager for clients, etc.
CertificateManager ca.GravelCertificateChain
// HTTP integration web server for Let's Encrypt.
CertificateServer http.Server
// Logger
Logger *logrus.Logger
TestRecords map[string]string
Client *http.Client
// testing reference.
t *wrappers.TestWrapper
// internal TLS configuration for the HTTP server.
serverTlsConfig *tls.Config
// internal TLS configuration for the HTTP client.
clientTlsConfig *tls.Config
Opts *GravelOpts
}
// Options used for configuring the integration environment.
type GravelOpts struct {
// Options used for the internal datastore.
DatabaseOpts *db.DatabaseOpts
// Options used for the integration DNS server
DnsOpts *dns.IntegrationServerOpts
// Options used for the Verification Authority.
VAOpts *va.VerificationAuthorityOpts
// Options used for configuring the Certificate Authority.
CAOpts *ca.CertificateAuthorityOpts
// Options used for configuring the Web Front End.
WfeOpts *wfe.WebFrontEndOpts
// Integrate the DNS instance with a testing suite.
EnableTestIntegration *testing.T
// Set to true if you want records automatically generated by Gravel to be added to the DNS server for automatic
// verification.
AutoUpdateAuthZRecords bool
// Address on which Gravel should listen.
ListenAddress string
// Logger to use.
Logger *logrus.Logger
}
// Generate a new set of default options for an integration environment.
func NewDefaultGravelOpts() *GravelOpts {
gopts := &GravelOpts{}
gopts.DnsOpts = dns.NewDefaultIntegrationServerOpts()
gopts.DatabaseOpts = db.NewDefaultDatabaseOpts()
gopts.VAOpts = va.NewDefaultVerificationAuthorityOpts()
gopts.CAOpts = ca.NewDefaultCertificateAuthorityOpts()
gopts.WfeOpts = wfe.NewDefaultWebFrontEndOpts()
gopts.Logger = logrus.New()
gopts.ListenAddress = "localhost:5000"
return gopts
}
// Generate a new Gravel integration harness.
func New(opts *GravelOpts) (*Gravel, error) {
g := &Gravel{
Opts: opts,
Logger: opts.Logger,
}
// map the test suite to the harness.
if opts.EnableTestIntegration != nil {
g.t = &wrappers.TestWrapper{T: opts.EnableTestIntegration}
}
// boot the integration dns server.
g.DnsServer = dns.NewIntegrationServer(opts.DnsOpts)
// build gravel.
g.Database = db.NewMemoryStore(opts.DatabaseOpts)
g.VerificationAuthority = va.New(opts.VAOpts)
g.CertificateAuthority = ca.New(g.Database, opts.CAOpts)
g.WebFrontEnd = wfe.New(g.Database, g.VerificationAuthority, g.CertificateAuthority, opts.WfeOpts)
// setup the tls configuration for the custom http transport we're building.
g.serverTlsConfig = &tls.Config{}
g.serverTlsConfig.Certificates = make([]tls.Certificate, 1)
// get the public key, private key, and encode the private key so we can create the transport.
rootPublicKey := g.CertificateAuthority.GetRootCert(0).PEM()
privateKeyBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(g.CertificateAuthority.GetRootKey(0)),
}
rootPrivateKey := pem.EncodeToMemory(privateKeyBlock)
var err error
g.serverTlsConfig.Certificates[0], err = tls.X509KeyPair(rootPublicKey, rootPrivateKey)
if err != nil {
return &Gravel{}, err
}
// generate our http client transport using the root certificates from the gravel certificate authority.
certPool, err := x509.SystemCertPool()
if err != nil {
return &Gravel{}, err
}
if ok := certPool.AppendCertsFromPEM(rootPublicKey); !ok {
g.t.Log("no gravel certs appended, only using system certificates")
}
g.clientTlsConfig = &tls.Config{
InsecureSkipVerify: true,
RootCAs: certPool,
}
if ok := certPool.AppendCertsFromPEM(rootPublicKey); !ok {
g.t.Log("no gravel certs appended, only using system certificates")
}
g.clientTlsConfig = &tls.Config{
InsecureSkipVerify: true,
RootCAs: certPool,
}
// build our client transport.
g.Client = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
Resolver: &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (conn net.Conn, e error) {
d := net.Dialer{}
return d.DialContext(ctx, "udp", fmt.Sprintf("localhost:%d", g.Opts.DnsOpts.DnsPort))
},
},
}).DialContext,
TLSHandshakeTimeout: 15 * time.Second,
ResponseHeaderTimeout: 15 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: g.clientTlsConfig,
},
}
return g, nil
}
// Start the integration harness web server.
func (g *Gravel) StartWebServer() {
g.CertificateServer = http.Server{
Addr: g.Opts.ListenAddress,
TLSConfig: g.serverTlsConfig,
Handler: g.WebFrontEnd.Handler(),
}
err := g.CertificateServer.ListenAndServeTLS("", "")
if err != nil {
if err.Error() != "http: Server closed" {
// todo (mxplusb): implement better error handling.
panic(err)
}
}
}
func (g *Gravel) StartDnsServer() {
// boot the integration DNS server instance.
go g.DnsServer.Start()
}