2021-08-24 12:48:30 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
2021-09-22 15:06:06 +00:00
|
|
|
"path/filepath"
|
2021-08-24 12:48:30 +00:00
|
|
|
"strings"
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
|
|
|
tls "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
|
|
|
discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
|
|
|
|
secretservice "github.com/envoyproxy/go-control-plane/envoy/service/secret/v3"
|
|
|
|
"github.com/envoyproxy/go-control-plane/pkg/cache/types"
|
|
|
|
cache "github.com/envoyproxy/go-control-plane/pkg/cache/v3"
|
|
|
|
xds "github.com/envoyproxy/go-control-plane/pkg/server/v3"
|
|
|
|
"github.com/hashicorp/go-hclog"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/grpclog"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
sdsTypeURI = "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
log := hclog.Default()
|
|
|
|
log.SetLevel(hclog.Trace)
|
2021-09-22 15:06:06 +00:00
|
|
|
|
|
|
|
if err := run(log); err != nil {
|
|
|
|
log.Error("failed to run SDS server", "err", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func run(log hclog.Logger) error {
|
2021-08-24 12:48:30 +00:00
|
|
|
cache := cache.NewLinearCache(sdsTypeURI)
|
|
|
|
|
|
|
|
addr := "0.0.0.0:1234"
|
|
|
|
if a := os.Getenv("SDS_BIND_ADDR"); a != "" {
|
|
|
|
addr = a
|
|
|
|
}
|
|
|
|
certPath := "certs"
|
|
|
|
if p := os.Getenv("SDS_CERT_PATH"); p != "" {
|
|
|
|
certPath = p
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := loadCertsFromPath(cache, log, certPath); err != nil {
|
2021-09-22 15:06:06 +00:00
|
|
|
return err
|
2021-08-24 12:48:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
l, err := net.Listen("tcp", addr)
|
|
|
|
if err != nil {
|
2021-09-22 15:06:06 +00:00
|
|
|
return err
|
2021-08-24 12:48:30 +00:00
|
|
|
}
|
|
|
|
defer l.Close()
|
|
|
|
log.Info("==> SDS listening", "addr", addr)
|
|
|
|
|
|
|
|
callbacks := makeLoggerCallbacks(log)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
2021-09-22 15:06:06 +00:00
|
|
|
defer cancel()
|
2021-08-24 12:48:30 +00:00
|
|
|
|
|
|
|
xdsServer := xds.NewServer(ctx, cache, callbacks)
|
|
|
|
grpcServer := grpc.NewServer()
|
|
|
|
grpclog.SetLogger(log.StandardLogger(nil))
|
|
|
|
|
|
|
|
secretservice.RegisterSecretDiscoveryServiceServer(grpcServer, xdsServer)
|
|
|
|
|
|
|
|
sigs := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
<-sigs
|
|
|
|
grpcServer.Stop()
|
|
|
|
cancel()
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err := grpcServer.Serve(l); err != nil {
|
2021-09-22 15:06:06 +00:00
|
|
|
return err
|
2021-08-24 12:48:30 +00:00
|
|
|
}
|
2021-09-22 15:06:06 +00:00
|
|
|
|
|
|
|
return nil
|
2021-08-24 12:48:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func loadCertsFromPath(cache *cache.LinearCache, log hclog.Logger, dir string) error {
|
|
|
|
entries, err := os.ReadDir(dir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, entry := range entries {
|
|
|
|
if entry.IsDir() {
|
|
|
|
continue
|
|
|
|
}
|
2021-09-22 15:06:06 +00:00
|
|
|
if !strings.HasSuffix(entry.Name(), ".crt") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
certName := strings.TrimSuffix(entry.Name(), ".crt")
|
2022-11-10 16:26:01 +00:00
|
|
|
cert, err := os.ReadFile(filepath.Join(dir, entry.Name()))
|
2021-09-22 15:06:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
keyFile := certName + ".key"
|
2022-11-10 16:26:01 +00:00
|
|
|
key, err := os.ReadFile(filepath.Join(dir, keyFile))
|
2021-09-22 15:06:06 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
var res tls.Secret
|
|
|
|
res.Name = certName
|
|
|
|
res.Type = &tls.Secret_TlsCertificate{
|
|
|
|
TlsCertificate: &tls.TlsCertificate{
|
|
|
|
CertificateChain: &core.DataSource{
|
|
|
|
Specifier: &core.DataSource_InlineBytes{
|
|
|
|
InlineBytes: cert,
|
2021-08-24 12:48:30 +00:00
|
|
|
},
|
2021-09-22 15:06:06 +00:00
|
|
|
},
|
|
|
|
PrivateKey: &core.DataSource{
|
|
|
|
Specifier: &core.DataSource_InlineBytes{
|
|
|
|
InlineBytes: key,
|
2021-08-24 12:48:30 +00:00
|
|
|
},
|
|
|
|
},
|
2021-09-22 15:06:06 +00:00
|
|
|
},
|
|
|
|
}
|
2021-08-24 12:48:30 +00:00
|
|
|
|
2021-09-22 15:06:06 +00:00
|
|
|
if err := cache.UpdateResource(certName, types.Resource(&res)); err != nil {
|
|
|
|
return err
|
2021-08-24 12:48:30 +00:00
|
|
|
}
|
2021-09-22 15:06:06 +00:00
|
|
|
log.Info("Loaded cert from file", "name", certName)
|
2021-08-24 12:48:30 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeLoggerCallbacks(log hclog.Logger) *xds.CallbackFuncs {
|
|
|
|
return &xds.CallbackFuncs{
|
|
|
|
|
|
|
|
StreamOpenFunc: func(_ context.Context, id int64, addr string) error {
|
|
|
|
log.Trace("gRPC stream opened", "id", id, "addr", addr)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
StreamClosedFunc: func(id int64) {
|
|
|
|
log.Trace("gRPC stream closed", "id", id)
|
|
|
|
},
|
|
|
|
StreamRequestFunc: func(id int64, req *discovery.DiscoveryRequest) error {
|
|
|
|
log.Trace("gRPC stream request", "id", id,
|
|
|
|
"node.id", req.Node.Id,
|
|
|
|
"req.typeURL", req.TypeUrl,
|
|
|
|
"req.version", req.VersionInfo,
|
|
|
|
)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
StreamResponseFunc: func(id int64, req *discovery.DiscoveryRequest, resp *discovery.DiscoveryResponse) {
|
2021-08-27 20:52:54 +00:00
|
|
|
log.Trace("gRPC stream response", "id", id,
|
2021-08-24 12:48:30 +00:00
|
|
|
"resp.typeURL", resp.TypeUrl,
|
|
|
|
"resp.version", resp.VersionInfo,
|
|
|
|
)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|