-
Notifications
You must be signed in to change notification settings - Fork 51
/
sds_server.go
694 lines (619 loc) · 22.1 KB
/
sds_server.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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
package envoyproxy
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"net"
"sync"
"time"
"context"
"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/secrets"
"go.aporeto.io/enforcerd/trireme-lib/policy"
"go.aporeto.io/enforcerd/trireme-lib/utils/cache"
"go.uber.org/zap"
"google.golang.org/grpc"
v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
envoy_api_v2_auth "github.com/envoyproxy/go-control-plane/envoy/api/v2/auth"
envoy_api_v2_core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
sds "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v2"
"github.com/golang/protobuf/ptypes"
//"github.com/gogo/protobuf/types"
"google.golang.org/grpc/metadata"
)
const (
// SdsSocketpath is the socket path on which the envoy will talk to the remoteEnforcer.
//SdsSocketpath = "@aporeto_envoy_sds"
SdsSocketpath = "127.0.0.1:2999"
//SdsSocketpath = "/var/run/sds/uds_path"
typeCertificate = "CERTIFICATE"
)
// Options to create a SDS server to task to envoy
type Options struct {
SocketPath string
}
// sdsCerts is the structure will pass the upstream certs downwards.
type sdsCerts struct {
key string
cert string
caPool *x509.CertPool
}
// SdsDiscoveryStream is the same as the sds.SecretDiscoveryService_StreamSecretsServer
type SdsDiscoveryStream interface {
Send(*v2.DiscoveryResponse) error
Recv() (*v2.DiscoveryRequest, error)
grpc.ServerStream
}
var _ sds.SecretDiscoveryServiceServer = &SdsServer{}
// SdsServer to talk with envoy for sds.
type SdsServer struct {
sdsGrpcServer *grpc.Server
sdsGrpcListener net.Listener
errCh chan error
puInfo *policy.PUInfo
cert *tls.Certificate
ca *x509.CertPool
keyPEM string
certPEM string
secrets secrets.Secrets
sync.RWMutex
// conncache is a cache of the sdsConnection, here the key is the connectionID and val is the secret.
conncache cache.DataStore
// updCertsChannel is used whenever there is a cert-update/Enfore
updCertsChannel chan sdsCerts
connMap map[string]bool
}
type secretItem struct {
CertificateChain []byte
PrivateKey []byte
RootCert []byte
// RootCertOwnedByCompoundSecret is true if this SecretItem was created by a
// K8S secret having both server cert/key and client ca and should be deleted
// with the secret.
RootCertOwnedByCompoundSecret bool
// ResourceName passed from envoy SDS discovery request.
// "ROOTCA" for root cert request, "default" for key/cert request.
ResourceName string
// Credential token passed from envoy, caClient uses this token to send
// CSR to CA to sign certificate.
Token string
// Version is used(together with token and ResourceName) to identify discovery request from
// envoy which is used only for confirm purpose.
Version string
CreatedTime time.Time
ExpireTime time.Time
}
// clientConn is ID for the connection between client and SDS server.
type clientConn struct {
clientID string
// the TLS cert information cached for this particular connection
secret *secretItem
// connectionID is the ID for each new request, make it a combo of nodeID+counter.
connectionID string
stream SdsDiscoveryStream
}
// NewSdsServer creates a instance of a server.
func NewSdsServer(contextID string, puInfo *policy.PUInfo, caPool *x509.CertPool, secrets secrets.Secrets) (*SdsServer, error) {
if puInfo == nil {
zap.L().Error("SDS Server: puInfo NIL ")
return nil, fmt.Errorf("the puinfo cannot be nil")
}
sdsOptions := &Options{SocketPath: SdsSocketpath}
sdsServer := &SdsServer{
puInfo: puInfo,
ca: caPool,
errCh: make(chan error),
secrets: secrets,
conncache: cache.NewCache("servers"),
updCertsChannel: make(chan sdsCerts),
connMap: make(map[string]bool),
}
if err := sdsServer.CreateSdsService(sdsOptions); err != nil {
zap.L().Error("SDS Server:Error while starting the envoy sds server.")
return nil, err
}
zap.L().Debug("SDS Server: SDS start success", zap.String("pu", puInfo.ContextID))
return sdsServer, nil
}
// CreateSdsService does the following
// 1. create grpc server.
// 2. create a listener on the Unix Domain Socket.
// 3.
func (s *SdsServer) CreateSdsService(options *Options) error { // nolint: unparam
s.sdsGrpcServer = grpc.NewServer()
s.register(s.sdsGrpcServer)
addr, err := net.ResolveTCPAddr("tcp", options.SocketPath)
if err != nil {
return err
}
nl, err := net.ListenTCP("tcp", addr)
if err != nil {
return err
}
// if err := os.Remove(options.SocketPath); err != nil && !os.IsNotExist(err) {
// zap.L().Error("SDS Server: envoy-reireme, failed to remove the udspath", zap.Error(err))
// return err
// }
// zap.L().Debug("SDS Server: Start listening on UDS path", zap.Any("socketPath", options.SocketPath))
// addr, _ := net.ResolveUnixAddr("unix", options.SocketPath)
// sdsGrpcListener, err := net.ListenUnix("unix", addr)
// if err != nil {
// zap.L().Error("SDS Server:cannot listen on the socketpath", zap.Error(err))
// return err
// }
// //make sure the socket path can be accessed.
// if _, err := os.Stat(options.SocketPath); err != nil {
// zap.L().Error("SDS Server: SDS uds file doesn't exist", zap.String("socketPath:", options.SocketPath))
// return fmt.Errorf("sds uds file %q doesn't exist", options.SocketPath)
// }
// if err := os.Chmod(options.SocketPath, 0666); err != nil {
// zap.L().Error("SDS Server: Failed to update permission", zap.String("socketPath:", options.SocketPath))
// return fmt.Errorf("failed to update %q permission", options.SocketPath)
// }
s.sdsGrpcListener = nl
zap.L().Debug("SDS Server: run the grpc server at", zap.Any("addr", s.sdsGrpcListener.Addr()))
s.Run()
return nil
}
// Run starts the sdsGrpcServer to serve
func (s *SdsServer) Run() {
go func() {
if s.sdsGrpcListener != nil {
if err := s.sdsGrpcServer.Serve(s.sdsGrpcListener); err != nil {
zap.L().Error("SDS Server: Error while serve", zap.Error(err))
s.errCh <- err
}
}
zap.L().Error("SDS Server: the listener is nil, cannot start the SDS server for", zap.String("puID", s.puInfo.ContextID))
}()
}
// Stop stops all the listeners and the grpc servers.
func (s *SdsServer) Stop() {
if s.sdsGrpcListener != nil {
s.sdsGrpcListener.Close() // nolint
}
if s.sdsGrpcServer != nil {
s.sdsGrpcServer.Stop()
}
}
// GracefulStop calls the function with the same name on the backing gRPC server
func (s *SdsServer) GracefulStop() {
s.sdsGrpcServer.GracefulStop()
}
// register adds the SDS handle to the grpc server
func (s *SdsServer) register(sdsGrpcServer *grpc.Server) {
zap.L().Debug("SDS Server: envoy-trireme registering the secret discovery")
sds.RegisterSecretDiscoveryServiceServer(sdsGrpcServer, s)
}
// UpdateSecrets updates the secrets
// Whenever the Envoy makes a request for certificate, the certs and keys are fetched from
// the Proxy.
func (s *SdsServer) UpdateSecrets(cert *tls.Certificate, caPool *x509.CertPool, secrets secrets.Secrets, certPEM, keyPEM string) {
s.Lock()
defer s.Unlock()
s.cert = cert
s.ca = caPool
//s.secrets = secrets
s.certPEM = certPEM
s.keyPEM = keyPEM
s.updCertsChannel <- sdsCerts{key: keyPEM, cert: certPEM, caPool: caPool}
}
// now implement the interfaces of the SDS grpc server.
// type SecretDiscoveryServiceServer interface {
// DeltaSecrets(SecretDiscoveryService_DeltaSecretsServer) error
// StreamSecrets(SecretDiscoveryService_StreamSecretsServer) error
// FetchSecrets(context.Context, *v2.DiscoveryRequest) (*v2.DiscoveryResponse, error)
// }
// DeltaSecrets checks for the delta and sends the changes.
func (s *SdsServer) DeltaSecrets(stream sds.SecretDiscoveryService_DeltaSecretsServer) error {
return nil
}
func startStreaming(stream SdsDiscoveryStream, discoveryReqCh chan *v2.DiscoveryRequest) {
defer close(discoveryReqCh)
for {
req, err := stream.Recv()
if err != nil {
zap.L().Error("SDS Server: Connection terminated with err", zap.Error(err))
return
}
discoveryReqCh <- req
}
}
// StreamSecrets is the function invoked by the envoy in-order to pull the certs, this also sends the response back to the envoy.
// It does the following:
// 1. create a receiver thread to stream the requests.
// 2. parse the discovery request.
// 3. track the request.
// 4. call the Aporeto api to generate the secret
func (s *SdsServer) StreamSecrets(stream sds.SecretDiscoveryService_StreamSecretsServer) error {
ctx := stream.Context()
token := ""
metadata, ok := metadata.FromIncomingContext(ctx)
if !ok {
return fmt.Errorf("unable to get metadata from incoming context")
}
if h, ok := metadata["authorization"]; ok {
if len(h) != 1 {
return fmt.Errorf("credential token from %q must have 1 value in gRPC metadata but got %d", "authorization", len(h))
}
token = h[0]
}
zap.L().Debug("SDS Server: IN stream secrets, token", zap.String("token", token))
// create new connection
conn := &clientConn{}
conn.stream = stream
discoveryReqCh := make(chan *v2.DiscoveryRequest, 1)
go startStreaming(stream, discoveryReqCh)
for {
// wait for the receiver thread to stream the request and send it to us over here.
select {
case req, ok := <-discoveryReqCh:
// if req == nil {
// zap.L().Warn("SDS Server: The request is nil")
// continue
// }
// Now check the following:
// 1. Return if stream is closed.
// 2. Return if its invalid request.
if !ok {
zap.L().Error("SDS Server: Receiver channel closed, which means the Receiver stream is closed")
return fmt.Errorf("Receiver closed the channel")
}
// then check for the req.Node
if req.Node == nil {
zap.L().Error("Invalid discovery request with no node")
return fmt.Errorf("invalid discovery request with no node")
}
if req.ErrorDetail != nil {
zap.L().Error("SDS Server: ERROR from envoy for processing the resource", zap.String("error", req.GetErrorDetail().String()))
continue
}
// now according to the Istio pilot SDS secret config we have 2 configs, this configs are pushed to envoy through Istio.
// 1. SDSDefaultResourceName is the default name in sdsconfig, used for fetching normal key/cert.
// 2. SDSRootResourceName is the sdsconfig name for root CA, used for fetching root cert.
// therefore from the above we receive 2 requests, 1 for default and 2 for the ROOTCA
// now check for the resourcename, it should atleast have one, else continue and stream the next request.
// according to the definition this could be empty.
if len(req.ResourceNames) == 0 {
continue
}
if len(req.ResourceNames) > 1 {
return fmt.Errorf("SDS Server: invalid resourceNames, greater than one")
}
resourceName := req.ResourceNames[0]
conn.clientID = req.Node.GetId()
//if len(conn.connectionID) == 0 {
conn.connectionID = createConnID(conn.clientID, resourceName)
// if this is not the 1st request and if the secret is already present then dont proceed as this is a ACK according to the XDS protocol.
if req.VersionInfo != "" && s.checkSecretPresent(conn.connectionID, req, token) {
zap.L().Warn("SDS Server: got a ACK from envoy", zap.String("connectionID", conn.connectionID), zap.String("resourceName", resourceName), zap.String("version", req.VersionInfo))
continue
}
secret := s.generateSecret(req, token)
if secret == nil {
zap.L().Error("SDS Server: the Certs cannot be served so return nil")
return fmt.Errorf("the aporeto SDS server cannot generate server, the certs are nil")
}
conn.secret = secret
s.conncache.AddOrUpdate(conn.connectionID, conn)
resp := &v2.DiscoveryResponse{
TypeUrl: "type.googleapis.com/envoy.api.v2.auth.Secret",
VersionInfo: secret.Version,
Nonce: secret.Version,
}
retSecret := &envoy_api_v2_auth.Secret{
Name: secret.ResourceName,
}
if secret.RootCert != nil {
retSecret.Type = getRootCert(secret)
} else {
retSecret.Type = getTLScerts(secret)
}
endSecret, err := ptypes.MarshalAny(retSecret)
if err != nil {
zap.L().Error("SDS Server: Cannot marshall the secret", zap.Error(err))
continue
}
resp.Resources = append(resp.Resources, endSecret)
if err = stream.Send(resp); err != nil {
zap.L().Error("SDS Server: Failed to send the resp cert", zap.Error(err))
return err
}
if secret.RootCert != nil {
zap.L().Debug("SDS Server: Successfully sent root cert", zap.String("rootCA", string(secret.RootCert)))
} else {
zap.L().Debug("SDS Server: Successfully sent default cert", zap.String("default cert", string(secret.CertificateChain)))
}
case updateCerts := <-s.updCertsChannel:
// 1st check if the connection is present
if _, err := s.conncache.Get(conn.connectionID); err != nil {
zap.L().Warn("SDS server: updCertsChannel, no connID found in cache,", zap.String("connID", conn.connectionID))
continue
}
fmt.Println("connID found now send certs")
if updateCerts.key != "" && updateCerts.cert != "" {
if err := s.sendUpdatedCerts(updateCerts, conn); err != nil {
zap.L().Error("SDS Server: send updated certs failed", zap.Error(err))
}
}
}
}
}
func (s *SdsServer) sendUpdatedCerts(apoSecret sdsCerts, conn *clientConn) error {
var err error
pemCert := []byte{} // nolint
t := time.Now()
if apoSecret.key != "" && apoSecret.cert != "" {
caPEM := s.secrets.CertAuthority()
pemCert, err = buildCertChain([]byte(apoSecret.cert), caPEM)
if err != nil {
zap.L().Error("SDS Server: Cannot build the cert chain")
return fmt.Errorf("SDS Server: Cannot build the cert chain")
}
resp := &v2.DiscoveryResponse{
TypeUrl: "type.googleapis.com/envoy.api.v2.auth.Secret",
VersionInfo: t.String(),
Nonce: t.String(),
}
retSecret := &envoy_api_v2_auth.Secret{
Name: "default",
}
retSecret.Type = &envoy_api_v2_auth.Secret_TlsCertificate{
TlsCertificate: &envoy_api_v2_auth.TlsCertificate{
CertificateChain: &envoy_api_v2_core.DataSource{
Specifier: &envoy_api_v2_core.DataSource_InlineBytes{
InlineBytes: pemCert,
},
},
PrivateKey: &envoy_api_v2_core.DataSource{
Specifier: &envoy_api_v2_core.DataSource_InlineBytes{
InlineBytes: []byte(apoSecret.key),
},
},
},
}
endSecret, err := ptypes.MarshalAny(retSecret)
if err != nil {
zap.L().Error("SDS Server: Cannot marshall the secret")
return fmt.Errorf("SDS Server: Cannot marshall the secret")
}
resp.Resources = append(resp.Resources, endSecret)
if err = conn.stream.Send(resp); err != nil {
zap.L().Error("SDS Server: Failed to send the resp cert")
return err
}
}
return nil
}
func (s *SdsServer) checkSecretPresent(connID string, req *v2.DiscoveryRequest, token string) bool {
val, err := s.conncache.Get(connID)
if err != nil {
return false
}
e := val.(*clientConn)
return e.secret.ResourceName == req.ResourceNames[0] && e.secret.Token == token && e.secret.Version == req.VersionInfo
}
func createConnID(clientID, resourceName string) string {
temp := clientID + resourceName
zap.L().Debug("SDS Server: generated a unique ID", zap.String("connID", temp), zap.String("resource", resourceName))
return temp
}
// FetchSecrets gets the discovery request and call the Aporeto backend to fetch the certs.
// 1. parse the discovery request.
// 2. track the request.
// 3. call the Aporeto api to generate the secret
func (s *SdsServer) FetchSecrets(ctx context.Context, req *v2.DiscoveryRequest) (*v2.DiscoveryResponse, error) {
token := ""
metadata, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, fmt.Errorf("unable to get metadata from incoming context")
}
if h, ok := metadata["authorization"]; ok {
if len(h) != 1 {
return nil, fmt.Errorf("credential token from %q must have 1 value in gRPC metadata but got %d", "authorization", len(h))
}
token = h[0]
}
zap.L().Info("SDS Server: IN stream secrets, token", zap.String("token", token))
secret := s.generateSecret(req, token)
resp := &v2.DiscoveryResponse{
TypeUrl: "type.googleapis.com/envoy.api.v2.auth.Secret",
}
retSecret := &envoy_api_v2_auth.Secret{
Name: secret.ResourceName,
}
if secret.RootCert != nil {
retSecret.Type = getRootCert(secret)
} else {
retSecret.Type = getTLScerts(secret)
}
endSecret, err := ptypes.MarshalAny(retSecret)
if err != nil {
zap.L().Error("SDS Server: Cannot marshall the secret")
return nil, err
}
resp.Resources = append(resp.Resources, endSecret)
if secret.RootCert != nil {
zap.L().Debug("SDS Server: Successfully sent root cert", zap.Any("rootCA", string(secret.RootCert)))
} else {
zap.L().Debug("SDS Server: Successfully sent default cert", zap.Any("default cert", string(secret.CertificateChain)))
}
return resp, nil
}
// generateSecret is the call which talks to the metadata API to fetch the certs.
func (s *SdsServer) generateSecret(req *v2.DiscoveryRequest, token string) *secretItem {
var err error
var pemCert []byte
t := time.Now()
var expTime time.Time
if s.puInfo.Policy == nil {
zap.L().Error("SDS Server: The policy is nil, Policy cannot be nil.")
}
// now fetch the certificates for the PU/Service.
certPEM, keyPEM, _ := s.puInfo.Policy.ServiceCertificates()
if certPEM == "" || keyPEM == "" {
zap.L().Error("SDS Server: the certs are empty")
return nil
}
caPEM := s.secrets.CertAuthority()
if req.ResourceNames[0] == "default" {
expTime, _ = getExpTimeFromCert([]byte(certPEM))
pemCert, _ = buildCertChain([]byte(certPEM), caPEM)
if err != nil {
zap.L().Error("SDS Server: Cannot build the cert chain")
return nil
}
} else {
expTime, _ = getExpTimeFromCert(caPEM)
pemCert, err = getTopRootCa(caPEM)
if err != nil {
zap.L().Error("SDS Server: Cannot build the Root cert chain")
}
}
if err != nil {
zap.L().Error("SDS Server: cannot get exp time", zap.Error(err))
return nil
}
if req.ResourceNames[0] == "default" {
return &secretItem{
CertificateChain: pemCert,
PrivateKey: []byte(keyPEM),
//PrivateKey: []byte(keyPEMdebug),
ResourceName: req.ResourceNames[0],
Token: token,
CreatedTime: t,
ExpireTime: expTime,
Version: t.String(),
}
}
return &secretItem{
RootCert: pemCert,
ResourceName: req.ResourceNames[0],
Token: token,
CreatedTime: t,
ExpireTime: expTime,
Version: t.String(),
}
}
func buildCertChain(certPEM, caPEM []byte) ([]byte, error) {
zap.L().Debug("SDS Server: BEFORE in buildCertChain certPEM", zap.String("certPEM", string(certPEM)), zap.String("caPEM", string(caPEM)))
certChain := []*x509.Certificate{}
//certPEMBlock := caPEM
clientPEMBlock := certPEM
derBlock, _ := pem.Decode(clientPEMBlock)
if derBlock != nil {
if derBlock.Type == typeCertificate {
cert, err := x509.ParseCertificate(derBlock.Bytes)
if err != nil {
return nil, err
}
certChain = append(certChain, cert)
} else {
return nil, fmt.Errorf("invalid pem block type: %s", derBlock.Type)
}
}
var certDERBlock *pem.Block
for {
certDERBlock, caPEM = pem.Decode(caPEM)
if certDERBlock == nil {
break
}
if certDERBlock.Type == typeCertificate {
cert, err := x509.ParseCertificate(certDERBlock.Bytes)
if err != nil {
return nil, err
}
certChain = append(certChain, cert)
} else {
return nil, fmt.Errorf("invalid pem block type: %s", certDERBlock.Type)
}
}
by, _ := x509CertChainToPem(certChain)
zap.L().Debug("SDS Server: After building the cert chain", zap.String("certChain", string(by)))
return x509CertChainToPem(certChain)
}
// x509CertToPem converts x509 to byte.
func x509CertToPem(cert *x509.Certificate) ([]byte, error) {
var pemBytes bytes.Buffer
if err := pem.Encode(&pemBytes, &pem.Block{Type: typeCertificate, Bytes: cert.Raw}); err != nil {
return nil, err
}
return pemBytes.Bytes(), nil
}
// x509CertChainToPem converts chain of x509 certs to byte.
func x509CertChainToPem(certChain []*x509.Certificate) ([]byte, error) {
var pemBytes bytes.Buffer
for _, cert := range certChain {
if err := pem.Encode(&pemBytes, &pem.Block{Type: typeCertificate, Bytes: cert.Raw}); err != nil {
return nil, err
}
}
return pemBytes.Bytes(), nil
}
// getTopRootCa get the top root CA
func getTopRootCa(certPEMBlock []byte) ([]byte, error) {
zap.L().Debug("SDS Server: BEFORE root cert", zap.String("root_cert", string(certPEMBlock)))
//rootCert := []*x509.Certificate{}
var certChain tls.Certificate
//certPEMBlock := []byte(rootcaBundle)
var certDERBlock *pem.Block
for {
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
if certDERBlock == nil {
break
}
if certDERBlock.Type == typeCertificate {
certChain.Certificate = append(certChain.Certificate, certDERBlock.Bytes)
}
}
zap.L().Debug("SDS Server: the root ca", zap.String("cert", string(certChain.Certificate[len(certChain.Certificate)-1])))
x509Cert, err := x509.ParseCertificate(certChain.Certificate[len(certChain.Certificate)-1])
if err != nil {
panic(err)
}
by, _ := x509CertToPem(x509Cert)
zap.L().Debug("SDS Server: After building the cert chain", zap.String("rootCert", string(by)))
return x509CertToPem(x509Cert)
}
// getExpTimeFromCert gets the exp time from the cert, assumning the cert is in pem encoded.
func getExpTimeFromCert(cert []byte) (time.Time, error) {
block, _ := pem.Decode(cert)
if block == nil {
zap.L().Error("getExpTimeFromCert: error while pem decode")
return time.Time{}, fmt.Errorf("Cannot decode the pem certs")
}
x509Cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
zap.L().Error("failed to parse the certs", zap.Error(err))
return time.Time{}, err
}
return x509Cert.NotAfter, nil
}
func getRootCert(secret *secretItem) *envoy_api_v2_auth.Secret_ValidationContext {
return &envoy_api_v2_auth.Secret_ValidationContext{
ValidationContext: &envoy_api_v2_auth.CertificateValidationContext{
TrustedCa: &envoy_api_v2_core.DataSource{
Specifier: &envoy_api_v2_core.DataSource_InlineBytes{
InlineBytes: secret.RootCert,
},
},
},
}
}
func getTLScerts(secret *secretItem) *envoy_api_v2_auth.Secret_TlsCertificate {
return &envoy_api_v2_auth.Secret_TlsCertificate{
TlsCertificate: &envoy_api_v2_auth.TlsCertificate{
CertificateChain: &envoy_api_v2_core.DataSource{
Specifier: &envoy_api_v2_core.DataSource_InlineBytes{
InlineBytes: secret.CertificateChain,
},
},
PrivateKey: &envoy_api_v2_core.DataSource{
Specifier: &envoy_api_v2_core.DataSource_InlineBytes{
InlineBytes: secret.PrivateKey,
},
},
},
}
}