1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package main
21
22 import (
23 "bytes"
24 "crypto/rand"
25 "crypto/rsa"
26 "crypto/x509"
27 "crypto/x509/pkix"
28 "encoding/pem"
29 "fmt"
30 "io"
31 "log"
32 "math/big"
33 "net"
34 "os"
35 "time"
36 )
37
38 const (
39 validityPeriod = 50 * 365 * 24 * time.Hour
40 )
41
42 func EncodeCertificate(w io.Writer, cert *x509.Certificate) error {
43 return pem.Encode(w, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
44 }
45
46 func EncodeKey(w io.Writer, priv *rsa.PrivateKey) error {
47 b, err := x509.MarshalPKCS8PrivateKey(priv)
48 if err != nil {
49 return fmt.Errorf("failed to marshal private key: %v", err)
50 }
51
52 return pem.Encode(w, &pem.Block{Type: "PRIVATE KEY", Bytes: b})
53 }
54
55 var serialNumber *big.Int
56
57 func init() {
58 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
59
60 var err error
61 serialNumber, err = rand.Int(rand.Reader, serialNumberLimit)
62 if err != nil {
63 panic(fmt.Errorf("failed to generate serial number: %v", err))
64 }
65 }
66
67 func SerialNumber() *big.Int {
68 var serial big.Int
69
70 serial.Set(serialNumber)
71 serialNumber.Add(&serial, big.NewInt(1))
72
73 return &serial
74 }
75
76 func GenerateCertificateAuthority(commonName string, parentCert *x509.Certificate, parentKey *rsa.PrivateKey) (*x509.Certificate, *rsa.PrivateKey, error) {
77 now := time.Now()
78
79 caKey, err := rsa.GenerateKey(rand.Reader, 4096)
80 if err != nil {
81 return nil, nil, fmt.Errorf("failed to generate CA private key: %v", err)
82 }
83
84 caCert := &x509.Certificate{
85 SerialNumber: SerialNumber(),
86 Subject: pkix.Name{
87 Country: []string{"US"},
88 Organization: []string{"Prometheus"},
89 OrganizationalUnit: []string{"Prometheus Certificate Authority"},
90 CommonName: commonName,
91 },
92 NotBefore: now,
93 NotAfter: now.Add(validityPeriod),
94 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
95 IsCA: true,
96 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
97 BasicConstraintsValid: true,
98 }
99
100 if parentCert == nil && parentKey == nil {
101 parentCert = caCert
102 parentKey = caKey
103 }
104
105 b, err := x509.CreateCertificate(rand.Reader, caCert, parentCert, &caKey.PublicKey, parentKey)
106 if err != nil {
107 return nil, nil, fmt.Errorf("failed to create CA certificate: %v", err)
108 }
109
110 caCert, err = x509.ParseCertificate(b)
111 if err != nil {
112 return nil, nil, fmt.Errorf("failed to decode CA certificate: %v", err)
113 }
114
115 return caCert, caKey, nil
116 }
117
118 func GenerateCertificate(caCert *x509.Certificate, caKey *rsa.PrivateKey, server bool, name string, ipAddresses ...net.IP) (*x509.Certificate, *rsa.PrivateKey, error) {
119 now := time.Now()
120
121 key, err := rsa.GenerateKey(rand.Reader, 4096)
122 if err != nil {
123 return nil, nil, fmt.Errorf("failed to generate private key: %v", err)
124 }
125
126 cert := &x509.Certificate{
127 SerialNumber: SerialNumber(),
128 Subject: pkix.Name{
129 Country: []string{"US"},
130 Organization: []string{"Prometheus"},
131 CommonName: name,
132 },
133 NotBefore: now,
134 NotAfter: now.Add(validityPeriod),
135 KeyUsage: x509.KeyUsageKeyEncipherment,
136 BasicConstraintsValid: true,
137 }
138
139 if server {
140 cert.DNSNames = []string{name}
141 cert.IPAddresses = ipAddresses
142 cert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
143 } else {
144 cert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
145 }
146
147 if caCert == nil && caKey == nil {
148 caCert = cert
149 caKey = key
150 }
151
152 b, err := x509.CreateCertificate(rand.Reader, cert, caCert, &key.PublicKey, caKey)
153 if err != nil {
154 return nil, nil, fmt.Errorf("failed to create certificate: %v", err)
155 }
156
157 cert, err = x509.ParseCertificate(b)
158 if err != nil {
159 return nil, nil, fmt.Errorf("failed to decode certificate: %v", err)
160 }
161
162 return cert, key, nil
163 }
164
165 func writeCertificateAndKey(path string, cert *x509.Certificate, key *rsa.PrivateKey) error {
166 var b bytes.Buffer
167
168 if err := EncodeCertificate(&b, cert); err != nil {
169 return err
170 }
171
172 if err := os.WriteFile(fmt.Sprintf("%s.crt", path), b.Bytes(), 0o644); err != nil {
173 return err
174 }
175
176 b.Reset()
177 if err := EncodeKey(&b, key); err != nil {
178 return err
179 }
180
181 if err := os.WriteFile(fmt.Sprintf("%s.key", path), b.Bytes(), 0o644); err != nil {
182 return err
183 }
184
185 return nil
186 }
187
188 func main() {
189 log.Println("Generating root CA")
190 rootCert, rootKey, err := GenerateCertificateAuthority("Prometheus Root CA", nil, nil)
191 if err != nil {
192 log.Fatal(err)
193 }
194
195 log.Println("Generating CA")
196 caCert, caKey, err := GenerateCertificateAuthority("Prometheus TLS CA", rootCert, rootKey)
197 if err != nil {
198 log.Fatal(err)
199 }
200
201 log.Println("Generating server certificate")
202 cert, key, err := GenerateCertificate(caCert, caKey, true, "localhost", net.IPv4(127, 0, 0, 1), net.IPv4(127, 0, 0, 0))
203 if err != nil {
204 log.Fatal(err)
205 }
206
207 if err := writeCertificateAndKey("testdata/server", cert, key); err != nil {
208 log.Fatal(err)
209 }
210
211 log.Println("Generating client certificate")
212 cert, key, err = GenerateCertificate(caCert, caKey, false, "localhost")
213 if err != nil {
214 log.Fatal(err)
215 }
216
217 if err := writeCertificateAndKey("testdata/client", cert, key); err != nil {
218 log.Fatal(err)
219 }
220
221 log.Println("Generating self-signed client certificate")
222 cert, key, err = GenerateCertificate(nil, nil, false, "localhost")
223 if err != nil {
224 log.Fatal(err)
225 }
226
227 if err := writeCertificateAndKey("testdata/self-signed-client", cert, key); err != nil {
228 log.Fatal(err)
229 }
230
231 log.Println("Generating CA bundle")
232 var b bytes.Buffer
233 if err := EncodeCertificate(&b, caCert); err != nil {
234 log.Fatal(err)
235 }
236
237 if err := EncodeCertificate(&b, rootCert); err != nil {
238 log.Fatal(err)
239 }
240
241 if err := os.WriteFile("testdata/tls-ca-chain.pem", b.Bytes(), 0o644); err != nil {
242 log.Fatal(err)
243 }
244 }
245
View as plain text