All import paths updated to git.wntrmute.dev/mc/. Bumps mcdsl to v1.2.0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
package grpcserver
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"path"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"git.wntrmute.dev/mc/metacrypt/internal/audit"
|
|
"git.wntrmute.dev/mc/metacrypt/internal/auth"
|
|
"git.wntrmute.dev/mc/metacrypt/internal/seal"
|
|
)
|
|
|
|
// sealInterceptor rejects calls with FailedPrecondition when the vault is
|
|
// sealed, for the listed methods. It is intended to run as a PreInterceptor
|
|
// in the mcdsl grpcserver chain, before logging and auth.
|
|
func sealInterceptor(sealMgr *seal.Manager, logger *slog.Logger, methods map[string]bool) grpc.UnaryServerInterceptor {
|
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
|
if !methods[info.FullMethod] {
|
|
return handler(ctx, req)
|
|
}
|
|
if sealMgr.State() != seal.StateUnsealed {
|
|
logger.Debug("grpc request rejected: vault sealed", "method", info.FullMethod)
|
|
return nil, status.Error(codes.FailedPrecondition, "vault is sealed")
|
|
}
|
|
return handler(ctx, req)
|
|
}
|
|
}
|
|
|
|
// auditInterceptor logs an audit event after each RPC completes. It is
|
|
// intended to run as a PostInterceptor in the mcdsl grpcserver chain,
|
|
// after auth so that caller info is available in the context via
|
|
// auth.TokenInfoFromContext.
|
|
func auditInterceptor(auditLog *audit.Logger) grpc.UnaryServerInterceptor {
|
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
|
resp, err := handler(ctx, req)
|
|
|
|
caller := "anonymous"
|
|
var roles []string
|
|
if ti := auth.TokenInfoFromContext(ctx); ti != nil {
|
|
caller = ti.Username
|
|
roles = ti.Roles
|
|
}
|
|
|
|
outcome := "success"
|
|
var errMsg string
|
|
if err != nil {
|
|
outcome = "error"
|
|
if st, ok := status.FromError(err); ok {
|
|
if st.Code() == codes.PermissionDenied || st.Code() == codes.Unauthenticated {
|
|
outcome = "denied"
|
|
}
|
|
errMsg = st.Message()
|
|
} else {
|
|
errMsg = err.Error()
|
|
}
|
|
}
|
|
|
|
auditLog.Log(ctx, audit.Event{
|
|
Caller: caller,
|
|
Roles: roles,
|
|
Operation: path.Base(info.FullMethod),
|
|
Resource: info.FullMethod,
|
|
Outcome: outcome,
|
|
Error: errMsg,
|
|
})
|
|
|
|
return resp, err
|
|
}
|
|
}
|