// Package grpcserver implements the gRPC server for Metacrypt. package grpcserver import ( "crypto/tls" "fmt" "log/slog" "net" "sync" "google.golang.org/grpc" "google.golang.org/grpc/credentials" pb "git.wntrmute.dev/kyle/metacrypt/gen/metacrypt/v2" internacme "git.wntrmute.dev/kyle/metacrypt/internal/acme" "git.wntrmute.dev/kyle/metacrypt/internal/auth" "git.wntrmute.dev/kyle/metacrypt/internal/config" "git.wntrmute.dev/kyle/metacrypt/internal/engine" "git.wntrmute.dev/kyle/metacrypt/internal/policy" "git.wntrmute.dev/kyle/metacrypt/internal/seal" ) // GRPCServer wraps the gRPC server and all service implementations. type GRPCServer struct { cfg *config.Config sealMgr *seal.Manager auth *auth.Authenticator policy *policy.Engine engines *engine.Registry logger *slog.Logger srv *grpc.Server acmeHandlers map[string]*internacme.Handler mu sync.Mutex } // New creates a new GRPCServer. func New(cfg *config.Config, sealMgr *seal.Manager, authenticator *auth.Authenticator, policyEngine *policy.Engine, engineRegistry *engine.Registry, logger *slog.Logger) *GRPCServer { return &GRPCServer{ cfg: cfg, sealMgr: sealMgr, auth: authenticator, policy: policyEngine, engines: engineRegistry, logger: logger, acmeHandlers: make(map[string]*internacme.Handler), } } // Start starts the gRPC server on cfg.Server.GRPCAddr. func (s *GRPCServer) Start() error { if s.cfg.Server.GRPCAddr == "" { s.logger.Info("grpc_addr not configured, gRPC server disabled") return nil } tlsCert, err := tls.LoadX509KeyPair(s.cfg.Server.TLSCert, s.cfg.Server.TLSKey) if err != nil { return fmt.Errorf("grpc: load TLS cert: %w", err) } tlsCfg := &tls.Config{ Certificates: []tls.Certificate{tlsCert}, MinVersion: tls.VersionTLS13, } creds := credentials.NewTLS(tlsCfg) interceptor := chainInterceptors( sealInterceptor(s.sealMgr, s.logger, sealRequiredMethods()), authInterceptor(s.auth, s.logger, authRequiredMethods()), adminInterceptor(s.logger, adminRequiredMethods()), ) s.srv = grpc.NewServer( grpc.Creds(creds), grpc.UnaryInterceptor(interceptor), ) pb.RegisterSystemServiceServer(s.srv, &systemServer{s: s}) pb.RegisterAuthServiceServer(s.srv, &authServer{s: s}) pb.RegisterEngineServiceServer(s.srv, &engineServer{s: s}) pb.RegisterPKIServiceServer(s.srv, &pkiServer{s: s}) pb.RegisterCAServiceServer(s.srv, &caServer{s: s}) pb.RegisterPolicyServiceServer(s.srv, &policyServer{s: s}) pb.RegisterBarrierServiceServer(s.srv, &barrierServer{s: s}) pb.RegisterACMEServiceServer(s.srv, &acmeServer{s: s}) lis, err := net.Listen("tcp", s.cfg.Server.GRPCAddr) if err != nil { return fmt.Errorf("grpc: listen %s: %w", s.cfg.Server.GRPCAddr, err) } s.logger.Info("starting gRPC server", "addr", s.cfg.Server.GRPCAddr) if err := s.srv.Serve(lis); err != nil { return fmt.Errorf("grpc: serve: %w", err) } return nil } // Shutdown gracefully stops the gRPC server. func (s *GRPCServer) Shutdown() { if s.srv != nil { s.srv.GracefulStop() } } // sealRequiredMethods returns the set of RPC full names that require the vault // to be unsealed. func sealRequiredMethods() map[string]bool { return map[string]bool{ "/metacrypt.v2.AuthService/Login": true, "/metacrypt.v2.AuthService/Logout": true, "/metacrypt.v2.AuthService/TokenInfo": true, "/metacrypt.v2.EngineService/Mount": true, "/metacrypt.v2.EngineService/Unmount": true, "/metacrypt.v2.EngineService/ListMounts": true, "/metacrypt.v2.PKIService/GetRootCert": true, "/metacrypt.v2.PKIService/GetChain": true, "/metacrypt.v2.PKIService/GetIssuerCert": true, "/metacrypt.v2.CAService/ImportRoot": true, "/metacrypt.v2.CAService/GetRoot": true, "/metacrypt.v2.CAService/CreateIssuer": true, "/metacrypt.v2.CAService/DeleteIssuer": true, "/metacrypt.v2.CAService/ListIssuers": true, "/metacrypt.v2.CAService/GetIssuer": true, "/metacrypt.v2.CAService/GetChain": true, "/metacrypt.v2.CAService/IssueCert": true, "/metacrypt.v2.CAService/GetCert": true, "/metacrypt.v2.CAService/ListCerts": true, "/metacrypt.v2.CAService/RenewCert": true, "/metacrypt.v2.CAService/SignCSR": true, "/metacrypt.v2.CAService/RevokeCert": true, "/metacrypt.v2.CAService/DeleteCert": true, "/metacrypt.v2.PolicyService/CreatePolicy": true, "/metacrypt.v2.PolicyService/ListPolicies": true, "/metacrypt.v2.PolicyService/GetPolicy": true, "/metacrypt.v2.PolicyService/DeletePolicy": true, "/metacrypt.v2.ACMEService/CreateEAB": true, "/metacrypt.v2.ACMEService/SetConfig": true, "/metacrypt.v2.ACMEService/ListAccounts": true, "/metacrypt.v2.ACMEService/ListOrders": true, "/metacrypt.v2.BarrierService/ListKeys": true, "/metacrypt.v2.BarrierService/RotateMEK": true, "/metacrypt.v2.BarrierService/RotateKey": true, "/metacrypt.v2.BarrierService/Migrate": true, } } // authRequiredMethods returns the set of RPC full names that require a valid token. func authRequiredMethods() map[string]bool { return map[string]bool{ "/metacrypt.v2.AuthService/Logout": true, "/metacrypt.v2.AuthService/TokenInfo": true, "/metacrypt.v2.EngineService/Mount": true, "/metacrypt.v2.EngineService/Unmount": true, "/metacrypt.v2.EngineService/ListMounts": true, "/metacrypt.v2.CAService/ImportRoot": true, "/metacrypt.v2.CAService/CreateIssuer": true, "/metacrypt.v2.CAService/DeleteIssuer": true, "/metacrypt.v2.CAService/ListIssuers": true, "/metacrypt.v2.CAService/IssueCert": true, "/metacrypt.v2.CAService/GetCert": true, "/metacrypt.v2.CAService/ListCerts": true, "/metacrypt.v2.CAService/RenewCert": true, "/metacrypt.v2.CAService/SignCSR": true, "/metacrypt.v2.CAService/RevokeCert": true, "/metacrypt.v2.CAService/DeleteCert": true, "/metacrypt.v2.PolicyService/CreatePolicy": true, "/metacrypt.v2.PolicyService/ListPolicies": true, "/metacrypt.v2.PolicyService/GetPolicy": true, "/metacrypt.v2.PolicyService/DeletePolicy": true, "/metacrypt.v2.ACMEService/CreateEAB": true, "/metacrypt.v2.ACMEService/SetConfig": true, "/metacrypt.v2.ACMEService/ListAccounts": true, "/metacrypt.v2.ACMEService/ListOrders": true, "/metacrypt.v2.BarrierService/ListKeys": true, "/metacrypt.v2.BarrierService/RotateMEK": true, "/metacrypt.v2.BarrierService/RotateKey": true, "/metacrypt.v2.BarrierService/Migrate": true, } } // adminRequiredMethods returns the set of RPC full names that require admin. func adminRequiredMethods() map[string]bool { return map[string]bool{ "/metacrypt.v2.SystemService/Seal": true, "/metacrypt.v2.EngineService/Mount": true, "/metacrypt.v2.EngineService/Unmount": true, "/metacrypt.v2.CAService/ImportRoot": true, "/metacrypt.v2.CAService/CreateIssuer": true, "/metacrypt.v2.CAService/DeleteIssuer": true, "/metacrypt.v2.CAService/RevokeCert": true, "/metacrypt.v2.CAService/DeleteCert": true, "/metacrypt.v2.PolicyService/CreatePolicy": true, "/metacrypt.v2.PolicyService/ListPolicies": true, "/metacrypt.v2.PolicyService/GetPolicy": true, "/metacrypt.v2.PolicyService/DeletePolicy": true, "/metacrypt.v2.ACMEService/SetConfig": true, "/metacrypt.v2.ACMEService/ListAccounts": true, "/metacrypt.v2.ACMEService/ListOrders": true, "/metacrypt.v2.BarrierService/ListKeys": true, "/metacrypt.v2.BarrierService/RotateMEK": true, "/metacrypt.v2.BarrierService/RotateKey": true, "/metacrypt.v2.BarrierService/Migrate": true, } }