mirror of
https://github.com/pomerium/pomerium.git
synced 2025-04-28 18:06:34 +02:00
223 lines
6.1 KiB
Go
223 lines
6.1 KiB
Go
package authorize
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
envoy_service_auth_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
|
|
"github.com/go-jose/go-jose/v3/jwt"
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/pomerium/pomerium/authorize/evaluator"
|
|
"github.com/pomerium/pomerium/internal/log"
|
|
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
|
"github.com/pomerium/pomerium/pkg/grpc/audit"
|
|
"github.com/pomerium/pomerium/pkg/grpc/databroker"
|
|
"github.com/pomerium/pomerium/pkg/grpc/session"
|
|
"github.com/pomerium/pomerium/pkg/grpc/user"
|
|
"github.com/pomerium/pomerium/pkg/grpcutil"
|
|
"github.com/pomerium/pomerium/pkg/storage"
|
|
"github.com/pomerium/pomerium/pkg/telemetry/requestid"
|
|
)
|
|
|
|
func (a *Authorize) logAuthorizeCheck(
|
|
ctx context.Context,
|
|
in *envoy_service_auth_v3.CheckRequest, out *envoy_service_auth_v3.CheckResponse,
|
|
res *evaluator.Result, s sessionOrServiceAccount, u *user.User,
|
|
) {
|
|
ctx, span := trace.StartSpan(ctx, "authorize.grpc.LogAuthorizeCheck")
|
|
defer span.End()
|
|
|
|
hdrs := getCheckRequestHeaders(in)
|
|
impersonateDetails := a.getImpersonateDetails(ctx, s)
|
|
|
|
evt := log.Info(ctx).Str("service", "authorize")
|
|
fields := a.currentOptions.Load().GetAuthorizeLogFields()
|
|
for _, field := range fields {
|
|
evt = populateLogEvent(ctx, field, evt, in, s, u, hdrs, impersonateDetails)
|
|
}
|
|
evt = log.HTTPHeaders(evt, fields, hdrs)
|
|
|
|
// result
|
|
if res != nil {
|
|
evt = evt.Bool("allow", res.Allow.Value)
|
|
if res.Allow.Value {
|
|
evt = evt.Strs("allow-why-true", res.Allow.Reasons.Strings())
|
|
} else {
|
|
evt = evt.Strs("allow-why-false", res.Allow.Reasons.Strings())
|
|
}
|
|
evt = evt.Bool("deny", res.Deny.Value)
|
|
if res.Deny.Value {
|
|
evt = evt.Strs("deny-why-true", res.Deny.Reasons.Strings())
|
|
} else {
|
|
evt = evt.Strs("deny-why-false", res.Deny.Reasons.Strings())
|
|
}
|
|
}
|
|
|
|
evt.Msg("authorize check")
|
|
|
|
if enc := a.state.Load().auditEncryptor; enc != nil {
|
|
ctx, span := trace.StartSpan(ctx, "authorize.grpc.AuditAuthorizeCheck")
|
|
defer span.End()
|
|
|
|
record := &audit.Record{
|
|
Request: in,
|
|
Response: out,
|
|
}
|
|
sealed, err := enc.Encrypt(record)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Err(err).Msg("authorize: error encrypting audit record")
|
|
return
|
|
}
|
|
log.Info(ctx).
|
|
Str("request-id", requestid.FromContext(ctx)).
|
|
EmbedObject(sealed).
|
|
Msg("audit log")
|
|
}
|
|
}
|
|
|
|
type impersonateDetails struct {
|
|
email string
|
|
sessionID string
|
|
userID string
|
|
}
|
|
|
|
func (a *Authorize) getImpersonateDetails(
|
|
ctx context.Context,
|
|
s sessionOrServiceAccount,
|
|
) *impersonateDetails {
|
|
var sessionID string
|
|
if s, ok := s.(*session.Session); ok {
|
|
sessionID = s.GetImpersonateSessionId()
|
|
}
|
|
if sessionID == "" {
|
|
return nil
|
|
}
|
|
|
|
querier := storage.GetQuerier(ctx)
|
|
|
|
req := &databroker.QueryRequest{
|
|
Type: grpcutil.GetTypeURL(new(session.Session)),
|
|
Limit: 1,
|
|
}
|
|
req.SetFilterByID(sessionID)
|
|
res, err := querier.Query(ctx, req)
|
|
if err != nil || len(res.GetRecords()) == 0 {
|
|
return nil
|
|
}
|
|
|
|
impersonatedSessionMsg, err := res.GetRecords()[0].GetData().UnmarshalNew()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
impersonatedSession, ok := impersonatedSessionMsg.(*session.Session)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
userID := impersonatedSession.GetUserId()
|
|
|
|
req = &databroker.QueryRequest{
|
|
Type: grpcutil.GetTypeURL(new(user.User)),
|
|
Limit: 1,
|
|
}
|
|
req.SetFilterByID(userID)
|
|
res, err = querier.Query(ctx, req)
|
|
if err != nil || len(res.GetRecords()) == 0 {
|
|
return nil
|
|
}
|
|
|
|
impersonatedUserMsg, err := res.GetRecords()[0].GetData().UnmarshalNew()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
impersonatedUser, ok := impersonatedUserMsg.(*user.User)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
email := impersonatedUser.GetEmail()
|
|
|
|
return &impersonateDetails{
|
|
sessionID: sessionID,
|
|
userID: userID,
|
|
email: email,
|
|
}
|
|
}
|
|
|
|
func populateLogEvent(
|
|
ctx context.Context,
|
|
field log.AuthorizeLogField,
|
|
evt *zerolog.Event,
|
|
in *envoy_service_auth_v3.CheckRequest,
|
|
s sessionOrServiceAccount,
|
|
u *user.User,
|
|
hdrs map[string]string,
|
|
impersonateDetails *impersonateDetails,
|
|
) *zerolog.Event {
|
|
path, query, _ := strings.Cut(in.GetAttributes().GetRequest().GetHttp().GetPath(), "?")
|
|
|
|
switch field {
|
|
case log.AuthorizeLogFieldCheckRequestID:
|
|
return evt.Str(string(field), hdrs["X-Request-Id"])
|
|
case log.AuthorizeLogFieldEmail:
|
|
return evt.Str(string(field), u.GetEmail())
|
|
case log.AuthorizeLogFieldHost:
|
|
return evt.Str(string(field), in.GetAttributes().GetRequest().GetHttp().GetHost())
|
|
case log.AuthorizeLogFieldIDToken:
|
|
if s, ok := s.(*session.Session); ok {
|
|
evt = evt.Str(string(field), s.GetIdToken().GetRaw())
|
|
}
|
|
return evt
|
|
case log.AuthorizeLogFieldIDTokenClaims:
|
|
if s, ok := s.(*session.Session); ok {
|
|
if t, err := jwt.ParseSigned(s.GetIdToken().GetRaw()); err == nil {
|
|
var m map[string]any
|
|
_ = t.UnsafeClaimsWithoutVerification(&m)
|
|
evt = evt.Interface(string(field), m)
|
|
}
|
|
}
|
|
return evt
|
|
case log.AuthorizeLogFieldImpersonateEmail:
|
|
if impersonateDetails != nil {
|
|
evt = evt.Str(string(field), impersonateDetails.email)
|
|
}
|
|
return evt
|
|
case log.AuthorizeLogFieldImpersonateSessionID:
|
|
if impersonateDetails != nil {
|
|
evt = evt.Str(string(field), impersonateDetails.sessionID)
|
|
}
|
|
return evt
|
|
case log.AuthorizeLogFieldImpersonateUserID:
|
|
if impersonateDetails != nil {
|
|
evt = evt.Str(string(field), impersonateDetails.userID)
|
|
}
|
|
return evt
|
|
case log.AuthorizeLogFieldIP:
|
|
return evt.Str(string(field), in.GetAttributes().GetSource().GetAddress().GetSocketAddress().GetAddress())
|
|
case log.AuthorizeLogFieldMethod:
|
|
return evt.Str(string(field), in.GetAttributes().GetRequest().GetHttp().GetMethod())
|
|
case log.AuthorizeLogFieldPath:
|
|
return evt.Str(string(field), path)
|
|
case log.AuthorizeLogFieldQuery:
|
|
return evt.Str(string(field), query)
|
|
case log.AuthorizeLogFieldRequestID:
|
|
return evt.Str(string(field), requestid.FromContext(ctx))
|
|
case log.AuthorizeLogFieldServiceAccountID:
|
|
if sa, ok := s.(*user.ServiceAccount); ok {
|
|
evt = evt.Str(string(field), sa.GetId())
|
|
}
|
|
return evt
|
|
case log.AuthorizeLogFieldSessionID:
|
|
if s, ok := s.(*session.Session); ok {
|
|
evt = evt.Str(string(field), s.GetId())
|
|
}
|
|
return evt
|
|
case log.AuthorizeLogFieldUser:
|
|
var userID string
|
|
if s != nil {
|
|
userID = s.GetUserId()
|
|
}
|
|
return evt.Str(string(field), userID)
|
|
default:
|
|
return evt
|
|
}
|
|
}
|