Skip to content

Commit

Permalink
Support TLS encryption for gRPC connections in Cloud Slack and Teams (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
pkosiec authored Dec 15, 2023
1 parent 8c46be5 commit 2955f95
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 11 deletions.
19 changes: 16 additions & 3 deletions pkg/bot/slack_cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/sourcegraph/conc/pool"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"

"github.com/kubeshop/botkube/internal/analytics"
Expand All @@ -33,6 +32,7 @@ import (
"github.com/kubeshop/botkube/pkg/execute"
"github.com/kubeshop/botkube/pkg/execute/command"
"github.com/kubeshop/botkube/pkg/formatx"
"github.com/kubeshop/botkube/pkg/grpcx"
"github.com/kubeshop/botkube/pkg/multierror"
"github.com/kubeshop/botkube/pkg/sliceutil"
)
Expand Down Expand Up @@ -169,8 +169,21 @@ func (b *CloudSlack) start(ctx context.Context) error {
return fmt.Errorf("while getting remote config for %s", config.CloudSlackCommPlatformIntegration)
}

creds := grpc.WithTransportCredentials(insecure.NewCredentials())
opts := []grpc.DialOption{creds,
b.log.WithFields(logrus.Fields{
"url": b.cfg.Server.URL,
"disableSecurity": b.cfg.Server.DisableTransportSecurity,
"tlsUseSystemCertPool": b.cfg.Server.TLS.UseSystemCertPool,
"tlsCACertificateLen": len(b.cfg.Server.TLS.CACertificate),
"tlsSkipVerify": b.cfg.Server.TLS.InsecureSkipVerify,
}).Debug("Creating gRPC connection to Cloud Teams...")

creds, err := grpcx.ClientTransportCredentials(b.log, b.cfg.Server)
if err != nil {
return fmt.Errorf("while creating gRPC credentials: %w", err)
}

opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithStreamInterceptor(cloudplatform.AddStreamingClientCredentials(remoteConfig)),
grpc.WithUnaryInterceptor(cloudplatform.AddUnaryClientCredentials(remoteConfig)),
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/bot/teams_cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ func (b *CloudTeams) GetStatus() health.PlatformStatus {
}

func (b *CloudTeams) start(ctx context.Context) error {
svc, err := newGrpcCloudTeamsConnector(b.log, b.cfg.Server.URL)
svc, err := newGrpcCloudTeamsConnector(b.log, b.cfg.Server)
if err != nil {
return fmt.Errorf("while creating gRPC connector")
return fmt.Errorf("while creating gRPC connector: %w", err)
}
defer svc.Shutdown()

Expand Down
23 changes: 18 additions & 5 deletions pkg/bot/teams_cloud_grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import (
"github.com/sourcegraph/conc/pool"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"

"github.com/kubeshop/botkube/internal/config/remote"
"github.com/kubeshop/botkube/pkg/api/cloudplatform"
pb "github.com/kubeshop/botkube/pkg/api/cloudteams"
"github.com/kubeshop/botkube/pkg/config"
"github.com/kubeshop/botkube/pkg/grpcx"
)

type grpcCloudTeamsConnector struct {
Expand All @@ -30,19 +30,32 @@ type grpcCloudTeamsConnector struct {
activityClient pb.CloudTeams_StreamActivityClient
}

func newGrpcCloudTeamsConnector(log logrus.FieldLogger, url string) (*grpcCloudTeamsConnector, error) {
func newGrpcCloudTeamsConnector(log logrus.FieldLogger, cfg config.GRPCServer) (*grpcCloudTeamsConnector, error) {
remoteConfig, ok := remote.GetConfig()
if !ok {
return nil, fmt.Errorf("while getting remote config for %q", config.CloudTeamsCommPlatformIntegration)
}
creds := grpc.WithTransportCredentials(insecure.NewCredentials())

log.WithFields(logrus.Fields{
"url": cfg.URL,
"disableSecurity": cfg.DisableTransportSecurity,
"tlsUseSystemCertPool": cfg.TLS.UseSystemCertPool,
"tlsCACertificateLen": len(cfg.TLS.CACertificate),
"tlsSkipVerify": cfg.TLS.InsecureSkipVerify,
}).Debug("Creating gRPC connection to Cloud Teams...")

creds, err := grpcx.ClientTransportCredentials(log, cfg)
if err != nil {
return nil, fmt.Errorf("while creating gRPC credentials: %w", err)
}

opts := []grpc.DialOption{
creds,
grpc.WithTransportCredentials(creds),
grpc.WithStreamInterceptor(cloudplatform.AddStreamingClientCredentials(remoteConfig)),
grpc.WithUnaryInterceptor(cloudplatform.AddUnaryClientCredentials(remoteConfig)),
}

conn, err := grpc.Dial(url, opts...)
conn, err := grpc.Dial(cfg.URL, opts...)
if err != nil {
return nil, fmt.Errorf("while creating gRCP connection: %w", err)
}
Expand Down
11 changes: 10 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,16 @@ type CloudSlack struct {

// GRPCServer config for gRPC server
type GRPCServer struct {
URL string `yaml:"url"`
URL string `yaml:"url"`
DisableTransportSecurity bool `yaml:"disableTransportSecurity"`
TLS GRPCServerTLSConfig `yaml:"tls"`
}

// GRPCServerTLSConfig describes gRPC server TLS configuration.m
type GRPCServerTLSConfig struct {
CACertificate []byte `yaml:"caCertificate"`
UseSystemCertPool bool `yaml:"useSystemCertPool"`
InsecureSkipVerify bool `yaml:"insecureSkipVerify"`
}

// Elasticsearch config auth settings
Expand Down
49 changes: 49 additions & 0 deletions pkg/grpcx/credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package grpcx

import (
"crypto/tls"
"crypto/x509"
"fmt"

"github.com/sirupsen/logrus"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"

"github.com/kubeshop/botkube/pkg/config"
)

// ClientTransportCredentials returns gRPC client transport credentials based on the provided configuration.
func ClientTransportCredentials(log logrus.FieldLogger, cfg config.GRPCServer) (credentials.TransportCredentials, error) {
if cfg.DisableTransportSecurity {
log.Warn("gRPC encryption is disabled. Disabling transport security...")
return insecure.NewCredentials(), nil
}

var (
certPool *x509.CertPool
err error
)
if cfg.TLS.UseSystemCertPool {
certPool, err = x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("while getting system certificate pool: %w", err)
}
} else {
certPool = x509.NewCertPool()
}

if len(cfg.TLS.CACertificate) != 0 {
log.Debug("Adding custom CA certificate for gRPC connection")
if !certPool.AppendCertsFromPEM(cfg.TLS.CACertificate) {
return nil, fmt.Errorf("failed to append CA certificate for gRPC connection")
}
}

if cfg.TLS.InsecureSkipVerify {
log.Warn("InsecureSkipVerify is enabled. Skipping TLS certificate verification...")
}

//nolint:gosec // G402: TLS InsecureSkipVerify may be true. - Yes, indeed - just for development purposes.
tlsCfg := &tls.Config{MinVersion: tls.VersionTLS13, InsecureSkipVerify: cfg.TLS.InsecureSkipVerify, RootCAs: certPool}
return credentials.NewTLS(tlsCfg), nil
}

0 comments on commit 2955f95

Please sign in to comment.