mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-08-07 07:14:50 +00:00
938dd6cb78
* Implemented mTLS support across services Extended gRPC configuration to support mutual TLS (mTLS) in agent and manager components for enhanced security. This includes the loading of Certificate Authority (CA) certificates, server, and client certificates, and keys. Updated README documentation to reflect the new environment variables required for mTLS configuration. Additionally, streamlined secure gRPC client connection setup and logging messages to indicate whether a service is running with TLS, mTLS, or without TLS. The change ensures secure communication between services by verifying both client and server identities, thus addressing potential security concerns in network-level interactions. Signed-off-by: SammyOina <sammyoina@gmail.com> * Enhance agent cert handling and update copyright - Implement function to create certificate files for the agent configuration dynamically, ensuring file paths are updated to reflect newly created files. This improves the agent's setup process by automating the certificate handling. - Update copyright clause to reflect the new owning entity, Ultraviolet, affirming correct attribution and compliance with legal requirements. - Refactor gRPC client connection code to remove redundant package alias, streamlining the codebase and improving readability. Signed-off-by: SammyOina <sammyoina@gmail.com> * Refactor cert loading with fallbacks Removed redundant certificate file creation logic in the agent module and introduced a more robust loading mechanism in the gRPC server module to support direct byte content aside from file paths. This change simplifies the initial setup process for the agent by removing the need to create certificate files preemptively, thereby streamlining deployment in environments with varying filesystem access. It supports using certificate contents directly, enhancing compatibility with in-memory configurations or environments where file storage may not be ideal. Signed-off-by: SammyOina <sammyoina@gmail.com> * fix lint Signed-off-by: SammyOina <sammyoina@gmail.com> --------- Signed-off-by: SammyOina <sammyoina@gmail.com>
143 lines
3.2 KiB
Go
143 lines
3.2 KiB
Go
// Copyright (c) Ultraviolet
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package grpc
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/absmach/magistrala/pkg/errors"
|
|
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
)
|
|
|
|
type security int
|
|
|
|
const (
|
|
withoutTLS security = iota
|
|
withTLS
|
|
withmTLS
|
|
)
|
|
|
|
var (
|
|
errGrpcConnect = errors.New("failed to connect to grpc server")
|
|
errGrpcClose = errors.New("failed to close grpc connection")
|
|
)
|
|
|
|
type Config struct {
|
|
ClientCert string `env:"CLIENT_CERT" envDefault:""`
|
|
ClientKey string `env:"CLIENT_KEY" envDefault:""`
|
|
ServerCAFile string `env:"SERVER_CA_CERTS" envDefault:""`
|
|
URL string `env:"URL" envDefault:"localhost:7001"`
|
|
Timeout time.Duration `env:"TIMEOUT" envDefault:"60s"`
|
|
}
|
|
|
|
type Client interface {
|
|
// Close closes gRPC connection.
|
|
Close() error
|
|
|
|
// Secure is used for pretty printing TLS info.
|
|
Secure() string
|
|
|
|
// Connection returns the gRPC connection.
|
|
Connection() *grpc.ClientConn
|
|
}
|
|
|
|
type client struct {
|
|
*grpc.ClientConn
|
|
cfg Config
|
|
secure security
|
|
}
|
|
|
|
var _ Client = (*client)(nil)
|
|
|
|
func NewClient(cfg Config) (Client, error) {
|
|
conn, secure, err := connect(cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &client{
|
|
ClientConn: conn,
|
|
cfg: cfg,
|
|
secure: secure,
|
|
}, nil
|
|
}
|
|
|
|
func (c *client) Close() error {
|
|
if err := c.ClientConn.Close(); err != nil {
|
|
return errors.Wrap(errGrpcClose, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *client) Secure() string {
|
|
switch c.secure {
|
|
case withTLS:
|
|
return "with TLS"
|
|
case withmTLS:
|
|
return "with mTLS"
|
|
case withoutTLS:
|
|
fallthrough
|
|
default:
|
|
return "without TLS"
|
|
}
|
|
}
|
|
|
|
func (c *client) Connection() *grpc.ClientConn {
|
|
return c.ClientConn
|
|
}
|
|
|
|
// connect creates new gRPC client and connect to gRPC server.
|
|
func connect(cfg Config) (*grpc.ClientConn, security, error) {
|
|
opts := []grpc.DialOption{
|
|
grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
|
|
}
|
|
secure := withoutTLS
|
|
tc := insecure.NewCredentials()
|
|
|
|
if cfg.ServerCAFile != "" {
|
|
tlsConfig := &tls.Config{}
|
|
|
|
// Loading root ca certificates file
|
|
rootCA, err := os.ReadFile(cfg.ServerCAFile)
|
|
if err != nil {
|
|
return nil, secure, fmt.Errorf("failed to load root ca file: %w", err)
|
|
}
|
|
if len(rootCA) > 0 {
|
|
capool := x509.NewCertPool()
|
|
if !capool.AppendCertsFromPEM(rootCA) {
|
|
return nil, secure, fmt.Errorf("failed to append root ca to tls.Config")
|
|
}
|
|
tlsConfig.RootCAs = capool
|
|
secure = withTLS
|
|
}
|
|
|
|
// Loading mtls certificates file
|
|
if cfg.ClientCert != "" || cfg.ClientKey != "" {
|
|
certificate, err := tls.LoadX509KeyPair(cfg.ClientCert, cfg.ClientKey)
|
|
if err != nil {
|
|
return nil, secure, fmt.Errorf("failed to client certificate and key %w", err)
|
|
}
|
|
tlsConfig.Certificates = []tls.Certificate{certificate}
|
|
secure = withmTLS
|
|
}
|
|
|
|
tc = credentials.NewTLS(tlsConfig)
|
|
}
|
|
|
|
opts = append(opts, grpc.WithTransportCredentials(tc))
|
|
|
|
conn, err := grpc.Dial(cfg.URL, opts...)
|
|
if err != nil {
|
|
return nil, secure, errors.Wrap(errGrpcConnect, err)
|
|
}
|
|
return conn, secure, nil
|
|
}
|