Files
metacrypt/internal/grpcserver/server.go
Kyle Isom 5c5d7e184e Fix ECDH zeroization, add audit logging, and remediate high findings
- Fix #61: handleRotateKey and handleDeleteUser now zeroize stored
  privBytes instead of calling Bytes() (which returns a copy). New
  state populates privBytes; old references nil'd for GC.
- Add audit logging subsystem (internal/audit) with structured event
  recording for cryptographic operations.
- Add audit log engine spec (engines/auditlog.md).
- Add ValidateName checks across all engines for path traversal (#48).
- Update AUDIT.md: all High findings resolved (0 open).
- Add REMEDIATION.md with detailed remediation tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 14:04:39 -07:00

308 lines
13 KiB
Go

// 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/audit"
"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
audit *audit.Logger
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, auditLog *audit.Logger, logger *slog.Logger) *GRPCServer {
return &GRPCServer{
cfg: cfg,
sealMgr: sealMgr,
auth: authenticator,
policy: policyEngine,
engines: engineRegistry,
audit: auditLog,
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()),
auditInterceptor(s.audit),
)
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.RegisterUserServiceServer(s.srv, &userServer{s: s})
pb.RegisterACMEServiceServer(s.srv, &acmeServer{s: s})
pb.RegisterSSHCAServiceServer(s.srv, &sshcaServer{s: s})
pb.RegisterTransitServiceServer(s.srv, &transitServer{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.UserService/Register": true,
"/metacrypt.v2.UserService/Provision": true,
"/metacrypt.v2.UserService/GetPublicKey": true,
"/metacrypt.v2.UserService/ListUsers": true,
"/metacrypt.v2.UserService/Encrypt": true,
"/metacrypt.v2.UserService/Decrypt": true,
"/metacrypt.v2.UserService/ReEncrypt": true,
"/metacrypt.v2.UserService/RotateKey": true,
"/metacrypt.v2.UserService/DeleteUser": 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,
// SSH CA.
"/metacrypt.v2.SSHCAService/GetCAPublicKey": true,
"/metacrypt.v2.SSHCAService/SignHost": true,
"/metacrypt.v2.SSHCAService/SignUser": true,
"/metacrypt.v2.SSHCAService/CreateProfile": true,
"/metacrypt.v2.SSHCAService/UpdateProfile": true,
"/metacrypt.v2.SSHCAService/GetProfile": true,
"/metacrypt.v2.SSHCAService/ListProfiles": true,
"/metacrypt.v2.SSHCAService/DeleteProfile": true,
"/metacrypt.v2.SSHCAService/GetCert": true,
"/metacrypt.v2.SSHCAService/ListCerts": true,
"/metacrypt.v2.SSHCAService/RevokeCert": true,
"/metacrypt.v2.SSHCAService/DeleteCert": true,
"/metacrypt.v2.SSHCAService/GetKRL": true,
// Transit.
"/metacrypt.v2.TransitService/CreateKey": true,
"/metacrypt.v2.TransitService/DeleteKey": true,
"/metacrypt.v2.TransitService/GetKey": true,
"/metacrypt.v2.TransitService/ListKeys": true,
"/metacrypt.v2.TransitService/RotateKey": true,
"/metacrypt.v2.TransitService/UpdateKeyConfig": true,
"/metacrypt.v2.TransitService/TrimKey": true,
"/metacrypt.v2.TransitService/Encrypt": true,
"/metacrypt.v2.TransitService/Decrypt": true,
"/metacrypt.v2.TransitService/Rewrap": true,
"/metacrypt.v2.TransitService/BatchEncrypt": true,
"/metacrypt.v2.TransitService/BatchDecrypt": true,
"/metacrypt.v2.TransitService/BatchRewrap": true,
"/metacrypt.v2.TransitService/Sign": true,
"/metacrypt.v2.TransitService/Verify": true,
"/metacrypt.v2.TransitService/Hmac": true,
"/metacrypt.v2.TransitService/GetPublicKey": 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.UserService/Register": true,
"/metacrypt.v2.UserService/Provision": true,
"/metacrypt.v2.UserService/GetPublicKey": true,
"/metacrypt.v2.UserService/ListUsers": true,
"/metacrypt.v2.UserService/Encrypt": true,
"/metacrypt.v2.UserService/Decrypt": true,
"/metacrypt.v2.UserService/ReEncrypt": true,
"/metacrypt.v2.UserService/RotateKey": true,
"/metacrypt.v2.UserService/DeleteUser": 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,
// SSH CA.
"/metacrypt.v2.SSHCAService/SignHost": true,
"/metacrypt.v2.SSHCAService/SignUser": true,
"/metacrypt.v2.SSHCAService/CreateProfile": true,
"/metacrypt.v2.SSHCAService/UpdateProfile": true,
"/metacrypt.v2.SSHCAService/GetProfile": true,
"/metacrypt.v2.SSHCAService/ListProfiles": true,
"/metacrypt.v2.SSHCAService/DeleteProfile": true,
"/metacrypt.v2.SSHCAService/GetCert": true,
"/metacrypt.v2.SSHCAService/ListCerts": true,
"/metacrypt.v2.SSHCAService/RevokeCert": true,
"/metacrypt.v2.SSHCAService/DeleteCert": true,
// Transit.
"/metacrypt.v2.TransitService/CreateKey": true,
"/metacrypt.v2.TransitService/DeleteKey": true,
"/metacrypt.v2.TransitService/GetKey": true,
"/metacrypt.v2.TransitService/ListKeys": true,
"/metacrypt.v2.TransitService/RotateKey": true,
"/metacrypt.v2.TransitService/UpdateKeyConfig": true,
"/metacrypt.v2.TransitService/TrimKey": true,
"/metacrypt.v2.TransitService/Encrypt": true,
"/metacrypt.v2.TransitService/Decrypt": true,
"/metacrypt.v2.TransitService/Rewrap": true,
"/metacrypt.v2.TransitService/BatchEncrypt": true,
"/metacrypt.v2.TransitService/BatchDecrypt": true,
"/metacrypt.v2.TransitService/BatchRewrap": true,
"/metacrypt.v2.TransitService/Sign": true,
"/metacrypt.v2.TransitService/Verify": true,
"/metacrypt.v2.TransitService/Hmac": true,
"/metacrypt.v2.TransitService/GetPublicKey": 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,
// User.
"/metacrypt.v2.UserService/Provision": true,
"/metacrypt.v2.UserService/DeleteUser": 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,
// SSH CA.
"/metacrypt.v2.SSHCAService/CreateProfile": true,
"/metacrypt.v2.SSHCAService/UpdateProfile": true,
"/metacrypt.v2.SSHCAService/DeleteProfile": true,
"/metacrypt.v2.SSHCAService/RevokeCert": true,
"/metacrypt.v2.SSHCAService/DeleteCert": true,
// Transit.
"/metacrypt.v2.TransitService/CreateKey": true,
"/metacrypt.v2.TransitService/DeleteKey": true,
"/metacrypt.v2.TransitService/RotateKey": true,
"/metacrypt.v2.TransitService/UpdateKeyConfig": true,
"/metacrypt.v2.TransitService/TrimKey": true,
}
}