authorize/log: remove audit logging (#5369)

This commit is contained in:
Denis Mishin 2024-11-22 14:32:52 -05:00 committed by GitHub
parent 3a8bdde211
commit 2bb70258c3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 829 additions and 1537 deletions

View file

@ -93,7 +93,7 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v3.CheckRe
if err != nil { if err != nil {
log.Ctx(ctx).Error().Err(err).Str("request-id", requestID).Msg("grpc check ext_authz_error") log.Ctx(ctx).Error().Err(err).Str("request-id", requestID).Msg("grpc check ext_authz_error")
} }
a.logAuthorizeCheck(ctx, in, resp, res, s, u) a.logAuthorizeCheck(ctx, in, res, s, u)
return resp, err return resp, err
} }

View file

@ -11,7 +11,6 @@ import (
"github.com/pomerium/pomerium/authorize/evaluator" "github.com/pomerium/pomerium/authorize/evaluator"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/telemetry/trace" "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/databroker"
"github.com/pomerium/pomerium/pkg/grpc/session" "github.com/pomerium/pomerium/pkg/grpc/session"
"github.com/pomerium/pomerium/pkg/grpc/user" "github.com/pomerium/pomerium/pkg/grpc/user"
@ -22,7 +21,7 @@ import (
func (a *Authorize) logAuthorizeCheck( func (a *Authorize) logAuthorizeCheck(
ctx context.Context, ctx context.Context,
in *envoy_service_auth_v3.CheckRequest, out *envoy_service_auth_v3.CheckResponse, in *envoy_service_auth_v3.CheckRequest,
res *evaluator.Result, s sessionOrServiceAccount, u *user.User, res *evaluator.Result, s sessionOrServiceAccount, u *user.User,
) { ) {
ctx, span := trace.StartSpan(ctx, "authorize.grpc.LogAuthorizeCheck") ctx, span := trace.StartSpan(ctx, "authorize.grpc.LogAuthorizeCheck")
@ -55,25 +54,6 @@ func (a *Authorize) logAuthorizeCheck(
} }
evt.Msg("authorize check") 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.Ctx(ctx).Info().
Str("request-id", requestid.FromContext(ctx)).
EmbedObject(sealed).
Msg("audit log")
}
} }
type impersonateDetails struct { type impersonateDetails struct {

View file

@ -13,7 +13,6 @@ import (
"github.com/pomerium/pomerium/internal/authenticateflow" "github.com/pomerium/pomerium/internal/authenticateflow"
"github.com/pomerium/pomerium/pkg/grpc" "github.com/pomerium/pomerium/pkg/grpc"
"github.com/pomerium/pomerium/pkg/grpc/databroker" "github.com/pomerium/pomerium/pkg/grpc/databroker"
"github.com/pomerium/pomerium/pkg/protoutil"
) )
var outboundGRPCConnection = new(grpc.CachedOutboundGRPClientConn) var outboundGRPCConnection = new(grpc.CachedOutboundGRPClientConn)
@ -27,7 +26,6 @@ type authorizeState struct {
evaluator *evaluator.Evaluator evaluator *evaluator.Evaluator
dataBrokerClientConnection *googlegrpc.ClientConn dataBrokerClientConnection *googlegrpc.ClientConn
dataBrokerClient databroker.DataBrokerServiceClient dataBrokerClient databroker.DataBrokerServiceClient
auditEncryptor *protoutil.Encryptor
sessionStore *config.SessionStore sessionStore *config.SessionStore
authenticateFlow authenticateFlow authenticateFlow authenticateFlow
} }
@ -71,14 +69,6 @@ func newAuthorizeStateFromConfig(
state.dataBrokerClientConnection = cc state.dataBrokerClientConnection = cc
state.dataBrokerClient = databroker.NewDataBrokerServiceClient(cc) state.dataBrokerClient = databroker.NewDataBrokerServiceClient(cc)
auditKey, err := cfg.Options.GetAuditKey()
if err != nil {
return nil, fmt.Errorf("authorize: invalid audit key: %w", err)
}
if auditKey != nil {
state.auditEncryptor = protoutil.NewEncryptor(auditKey)
}
state.sessionStore, err = config.NewSessionStore(cfg.Options) state.sessionStore, err = config.NewSessionStore(cfg.Options)
if err != nil { if err != nil {
return nil, fmt.Errorf("authorize: invalid session store: %w", err) return nil, fmt.Errorf("authorize: invalid session store: %w", err)

View file

@ -1,41 +0,0 @@
package config
import (
"encoding/base64"
"github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/grpc/crypt"
)
// A PublicKeyEncryptionKeyOptions represents options for a public key encryption key.
type PublicKeyEncryptionKeyOptions struct {
ID string `mapstructure:"id" yaml:"id"`
Data string `mapstructure:"data" yaml:"data"` // base64-encoded
}
// GetAuditKey gets the audit key from the options. If no audit key is provided it will return (nil, nil).
func (o *Options) GetAuditKey() (*cryptutil.PublicKeyEncryptionKey, error) {
if o.AuditKey == nil {
return nil, nil
}
raw, err := base64.StdEncoding.DecodeString(o.AuditKey.Data)
if err != nil {
return nil, err
}
return cryptutil.NewPublicKeyEncryptionKeyWithID(o.AuditKey.ID, raw)
}
func (o *PublicKeyEncryptionKeyOptions) ToProto() *crypt.PublicKeyEncryptionKey {
if o == nil {
return nil
}
decoded, err := base64.StdEncoding.DecodeString(o.Data)
if err != nil {
return nil
}
return &crypt.PublicKeyEncryptionKey{
Id: o.ID,
Data: decoded,
}
}

View file

@ -36,7 +36,6 @@ import (
"github.com/pomerium/pomerium/internal/urlutil" "github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/pkg/cryptutil" "github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/grpc/config" "github.com/pomerium/pomerium/pkg/grpc/config"
"github.com/pomerium/pomerium/pkg/grpc/crypt"
"github.com/pomerium/pomerium/pkg/hpke" "github.com/pomerium/pomerium/pkg/hpke"
"github.com/pomerium/pomerium/pkg/identity/oauth" "github.com/pomerium/pomerium/pkg/identity/oauth"
"github.com/pomerium/pomerium/pkg/identity/oauth/apple" "github.com/pomerium/pomerium/pkg/identity/oauth/apple"
@ -287,8 +286,6 @@ type Options struct {
// CodecType is the codec to use for downstream connections. // CodecType is the codec to use for downstream connections.
CodecType CodecType `mapstructure:"codec_type" yaml:"codec_type"` CodecType CodecType `mapstructure:"codec_type" yaml:"codec_type"`
AuditKey *PublicKeyEncryptionKeyOptions `mapstructure:"audit_key"`
BrandingOptions httputil.BrandingOptions BrandingOptions httputil.BrandingOptions
PassIdentityHeaders *bool `mapstructure:"pass_identity_headers" yaml:"pass_identity_headers"` PassIdentityHeaders *bool `mapstructure:"pass_identity_headers" yaml:"pass_identity_headers"`
@ -1551,7 +1548,6 @@ func (o *Options) ApplySettings(ctx context.Context, certsIndex *cryptutil.Certi
set(&o.EnvoyBindConfigSourceAddress, settings.EnvoyBindConfigSourceAddress) set(&o.EnvoyBindConfigSourceAddress, settings.EnvoyBindConfigSourceAddress)
o.EnvoyBindConfigFreebind = null.BoolFromPtr(settings.EnvoyBindConfigFreebind) o.EnvoyBindConfigFreebind = null.BoolFromPtr(settings.EnvoyBindConfigFreebind)
setSlice(&o.ProgrammaticRedirectDomainWhitelist, settings.ProgrammaticRedirectDomainWhitelist) setSlice(&o.ProgrammaticRedirectDomainWhitelist, settings.ProgrammaticRedirectDomainWhitelist)
setAuditKey(&o.AuditKey, settings.AuditKey)
setCodecType(&o.CodecType, settings.CodecType) setCodecType(&o.CodecType, settings.CodecType)
setOptional(&o.PassIdentityHeaders, settings.PassIdentityHeaders) setOptional(&o.PassIdentityHeaders, settings.PassIdentityHeaders)
o.BrandingOptions = settings o.BrandingOptions = settings
@ -1639,7 +1635,6 @@ func (o *Options) ToProto() *config.Config {
copySrcToOptionalDest(&settings.EnvoyBindConfigSourceAddress, &o.EnvoyBindConfigSourceAddress) copySrcToOptionalDest(&settings.EnvoyBindConfigSourceAddress, &o.EnvoyBindConfigSourceAddress)
settings.EnvoyBindConfigFreebind = o.EnvoyBindConfigFreebind.Ptr() settings.EnvoyBindConfigFreebind = o.EnvoyBindConfigFreebind.Ptr()
settings.ProgrammaticRedirectDomainWhitelist = o.ProgrammaticRedirectDomainWhitelist settings.ProgrammaticRedirectDomainWhitelist = o.ProgrammaticRedirectDomainWhitelist
settings.AuditKey = o.AuditKey.ToProto()
if o.CodecType != "" { if o.CodecType != "" {
codecType := o.CodecType.ToEnvoy() codecType := o.CodecType.ToEnvoy()
settings.CodecType = &codecType settings.CodecType = &codecType
@ -1876,16 +1871,6 @@ func setAuthorizeLogFields(dst *[]log.AuthorizeLogField, src *config.Settings_St
} }
} }
func setAuditKey(dst **PublicKeyEncryptionKeyOptions, src *crypt.PublicKeyEncryptionKey) {
if src == nil {
return
}
*dst = &PublicKeyEncryptionKeyOptions{
ID: src.GetId(),
Data: base64.StdEncoding.EncodeToString(src.GetData()),
}
}
func setCodecType(dst *CodecType, src *envoy_http_connection_manager.HttpConnectionManager_CodecType) { func setCodecType(dst *CodecType, src *envoy_http_connection_manager.HttpConnectionManager_CodecType) {
if src == nil { if src == nil {
return return

File diff suppressed because it is too large Load diff

View file

@ -8,8 +8,6 @@ import "google/protobuf/struct.proto";
import "envoy/config/cluster/v3/cluster.proto"; import "envoy/config/cluster/v3/cluster.proto";
import "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto"; import "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto";
import "crypt/crypt.proto";
message Config { message Config {
string name = 1; string name = 1;
repeated Route routes = 2; repeated Route routes = 2;
@ -245,7 +243,7 @@ message Settings {
repeated string programmatic_redirect_domain_whitelist = 68; repeated string programmatic_redirect_domain_whitelist = 68;
optional envoy.extensions.filters.network.http_connection_manager.v3 optional envoy.extensions.filters.network.http_connection_manager.v3
.HttpConnectionManager.CodecType codec_type = 73; .HttpConnectionManager.CodecType codec_type = 73;
optional pomerium.crypt.PublicKeyEncryptionKey audit_key = 72; // optional pomerium.crypt.PublicKeyEncryptionKey audit_key = 72;
optional string primary_color = 85; optional string primary_color = 85;
optional string secondary_color = 86; optional string secondary_color = 86;
optional string darkmode_primary_color = 87; optional string darkmode_primary_color = 87;

View file

@ -1,27 +0,0 @@
// Package crypt contains cryptographic protobuf messages.
package crypt
import (
"encoding/base64"
"github.com/rs/zerolog"
"google.golang.org/protobuf/encoding/protojson"
)
// MarshalZerologObject fills the zerolog event fields.
func (x *SealedMessage) MarshalZerologObject(evt *zerolog.Event) {
evt.Str("@type", "type.googleapis.com/pomerium.crypt.SealedMessage").
Str("key_id", x.GetKeyId()).
Str("data_encryption_key", base64.StdEncoding.EncodeToString(x.GetDataEncryptionKey())).
Str("message_type", x.GetMessageType()).
Str("encrypted_message", base64.StdEncoding.EncodeToString(x.GetEncryptedMessage()))
}
// UnmarshalFromRawZerolog unmarshals a raw zerolog object into the sealed message.
func (x *SealedMessage) UnmarshalFromRawZerolog(raw []byte) error {
opts := protojson.UnmarshalOptions{
AllowPartial: true,
DiscardUnknown: true,
}
return opts.Unmarshal(raw, x)
}

View file

@ -1,254 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.2
// protoc v3.21.7
// source: crypt.proto
package crypt
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// A SealedMessage is an encrypted protobuf message.
type SealedMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The Curve25519 public key used to encrypt the data encryption key.
KeyId string `protobuf:"bytes,1,opt,name=key_id,json=keyId,proto3" json:"key_id,omitempty"`
// The XChacha20poly1305 key used to encrypt the data,
// itself stored encrypted by the Curve25519 public key.
DataEncryptionKey []byte `protobuf:"bytes,2,opt,name=data_encryption_key,json=dataEncryptionKey,proto3" json:"data_encryption_key,omitempty"`
// The message type indicates the type of the protobuf message stored encrypted in encrypted_message.
MessageType string `protobuf:"bytes,3,opt,name=message_type,json=messageType,proto3" json:"message_type,omitempty"`
// An arbitrary encrypted protobuf message (marshaled as protojson before encryption).
EncryptedMessage []byte `protobuf:"bytes,4,opt,name=encrypted_message,json=encryptedMessage,proto3" json:"encrypted_message,omitempty"`
}
func (x *SealedMessage) Reset() {
*x = SealedMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_crypt_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SealedMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SealedMessage) ProtoMessage() {}
func (x *SealedMessage) ProtoReflect() protoreflect.Message {
mi := &file_crypt_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SealedMessage.ProtoReflect.Descriptor instead.
func (*SealedMessage) Descriptor() ([]byte, []int) {
return file_crypt_proto_rawDescGZIP(), []int{0}
}
func (x *SealedMessage) GetKeyId() string {
if x != nil {
return x.KeyId
}
return ""
}
func (x *SealedMessage) GetDataEncryptionKey() []byte {
if x != nil {
return x.DataEncryptionKey
}
return nil
}
func (x *SealedMessage) GetMessageType() string {
if x != nil {
return x.MessageType
}
return ""
}
func (x *SealedMessage) GetEncryptedMessage() []byte {
if x != nil {
return x.EncryptedMessage
}
return nil
}
type PublicKeyEncryptionKey struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *PublicKeyEncryptionKey) Reset() {
*x = PublicKeyEncryptionKey{}
if protoimpl.UnsafeEnabled {
mi := &file_crypt_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PublicKeyEncryptionKey) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PublicKeyEncryptionKey) ProtoMessage() {}
func (x *PublicKeyEncryptionKey) ProtoReflect() protoreflect.Message {
mi := &file_crypt_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PublicKeyEncryptionKey.ProtoReflect.Descriptor instead.
func (*PublicKeyEncryptionKey) Descriptor() ([]byte, []int) {
return file_crypt_proto_rawDescGZIP(), []int{1}
}
func (x *PublicKeyEncryptionKey) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *PublicKeyEncryptionKey) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
var File_crypt_proto protoreflect.FileDescriptor
var file_crypt_proto_rawDesc = []byte{
0x0a, 0x0b, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x70,
0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x22, 0xa6, 0x01,
0x0a, 0x0d, 0x53, 0x65, 0x61, 0x6c, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
0x15, 0x0a, 0x06, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x6b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x65,
0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x11, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x6e, 0x63,
0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x3c, 0x0a, 0x16, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
0x64, 0x61, 0x74, 0x61, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65,
0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x72,
0x79, 0x70, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_crypt_proto_rawDescOnce sync.Once
file_crypt_proto_rawDescData = file_crypt_proto_rawDesc
)
func file_crypt_proto_rawDescGZIP() []byte {
file_crypt_proto_rawDescOnce.Do(func() {
file_crypt_proto_rawDescData = protoimpl.X.CompressGZIP(file_crypt_proto_rawDescData)
})
return file_crypt_proto_rawDescData
}
var file_crypt_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_crypt_proto_goTypes = []any{
(*SealedMessage)(nil), // 0: pomerium.crypt.SealedMessage
(*PublicKeyEncryptionKey)(nil), // 1: pomerium.crypt.PublicKeyEncryptionKey
}
var file_crypt_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_crypt_proto_init() }
func file_crypt_proto_init() {
if File_crypt_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_crypt_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*SealedMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_crypt_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*PublicKeyEncryptionKey); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_crypt_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_crypt_proto_goTypes,
DependencyIndexes: file_crypt_proto_depIdxs,
MessageInfos: file_crypt_proto_msgTypes,
}.Build()
File_crypt_proto = out.File
file_crypt_proto_rawDesc = nil
file_crypt_proto_goTypes = nil
file_crypt_proto_depIdxs = nil
}

View file

@ -1,22 +0,0 @@
syntax = "proto3";
package pomerium.crypt;
option go_package = "github.com/pomerium/pomerium/pkg/grpc/crypt";
// A SealedMessage is an encrypted protobuf message.
message SealedMessage {
// The Curve25519 public key used to encrypt the data encryption key.
string key_id = 1;
// The XChacha20poly1305 key used to encrypt the data,
// itself stored encrypted by the Curve25519 public key.
bytes data_encryption_key = 2;
// The message type indicates the type of the protobuf message stored encrypted in encrypted_message.
string message_type = 3;
// An arbitrary encrypted protobuf message (marshaled as protojson before encryption).
bytes encrypted_message = 4;
}
message PublicKeyEncryptionKey {
string id = 1;
bytes data = 2;
}

View file

@ -1,29 +0,0 @@
package crypt
import (
"bytes"
"testing"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestZerolog(t *testing.T) {
var buf bytes.Buffer
log := zerolog.New(&buf)
log.Info().EmbedObject(&SealedMessage{
KeyId: "KEY_ID",
DataEncryptionKey: []byte("DATA_ENCRYPTION_KEY"),
MessageType: "MESSAGE_TYPE",
EncryptedMessage: []byte("ENCRYPTED_MESSAGE"),
}).Msg("TEST")
var msg SealedMessage
err := msg.UnmarshalFromRawZerolog(buf.Bytes())
require.NoError(t, err)
assert.Equal(t, "KEY_ID", msg.GetKeyId())
assert.Equal(t, []byte("DATA_ENCRYPTION_KEY"), msg.GetDataEncryptionKey())
assert.Equal(t, "MESSAGE_TYPE", msg.GetMessageType())
assert.Equal(t, []byte("ENCRYPTED_MESSAGE"), msg.GetEncryptedMessage())
}

View file

@ -75,7 +75,6 @@ done
_sub_directories=( _sub_directories=(
audit audit
cli cli
crypt
config config
databroker databroker
device device

View file

@ -1,169 +0,0 @@
package protoutil
import (
"fmt"
"sync"
"time"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"
"github.com/pomerium/pomerium/pkg/cryptutil"
cryptpb "github.com/pomerium/pomerium/pkg/grpc/crypt"
)
// An Encryptor encrypts protobuf messages using a key encryption key and periodically rotated
// generated data encryption keys.
type Encryptor struct {
kek *cryptutil.PublicKeyEncryptionKey
rotateEvery time.Duration
sync.RWMutex
nextRotate time.Time
dek *cryptutil.DataEncryptionKey
encryptedDEK []byte
}
// NewEncryptor returns a new protobuf Encryptor.
func NewEncryptor(kek *cryptutil.PublicKeyEncryptionKey) *Encryptor {
return &Encryptor{
kek: kek,
rotateEvery: time.Hour,
}
}
func (enc *Encryptor) getDataEncryptionKey() (*cryptutil.DataEncryptionKey, []byte, error) {
// double-checked locking
// first time we do a read only lookup
enc.RLock()
dek, encryptedDEK, err := enc.getDataEncryptionKeyLocked(true)
enc.RUnlock()
if err != nil {
return nil, nil, err
} else if dek != nil {
return dek, encryptedDEK, nil
}
// second time we do a read/write lookup
enc.Lock()
dek, encryptedDEK, err = enc.getDataEncryptionKeyLocked(false)
enc.Unlock()
return dek, encryptedDEK, err
}
func (enc *Encryptor) getDataEncryptionKeyLocked(readOnly bool) (*cryptutil.DataEncryptionKey, []byte, error) {
needsNewKey := enc.dek == nil || time.Now().After(enc.nextRotate)
if !needsNewKey {
return enc.dek, enc.encryptedDEK, nil
}
if readOnly {
return nil, nil, nil
}
// generate a new data encryption key
dek, err := cryptutil.GenerateDataEncryptionKey()
if err != nil {
return nil, nil, err
}
// seal the data encryption key using the key encryption key
encryptedDEK, err := enc.kek.EncryptDataEncryptionKey(dek)
if err != nil {
return nil, nil, err
}
enc.dek = dek
enc.encryptedDEK = encryptedDEK
enc.nextRotate = time.Now().Add(enc.rotateEvery)
return enc.dek, enc.encryptedDEK, nil
}
// Encrypt encrypts a protobuf message.
func (enc *Encryptor) Encrypt(msg proto.Message) (*cryptpb.SealedMessage, error) {
// get the data encryption key
dek, encryptedDEK, err := enc.getDataEncryptionKey()
if err != nil {
return nil, err
}
plaintext, err := protojson.Marshal(msg)
if err != nil {
return nil, err
}
ciphertext := dek.Encrypt(plaintext)
return &cryptpb.SealedMessage{
KeyId: enc.kek.ID(),
DataEncryptionKey: encryptedDEK,
MessageType: GetTypeURL(msg),
EncryptedMessage: ciphertext,
}, nil
}
// A Decryptor decrypts encrypted protobuf messages.
type Decryptor struct {
keySource cryptutil.KeyEncryptionKeySource
dekCache *cryptutil.DataEncryptionKeyCache
}
// NewDecryptor creates a new decryptor.
func NewDecryptor(keySource cryptutil.KeyEncryptionKeySource) *Decryptor {
return &Decryptor{
keySource: keySource,
dekCache: cryptutil.NewDataEncryptionKeyCache(),
}
}
func (dec *Decryptor) getDataEncryptionKey(keyEncryptionKeyID string, encryptedDEK []byte) (*cryptutil.DataEncryptionKey, error) {
// return a dek if its already cached
dek, ok := dec.dekCache.Get(encryptedDEK)
if ok {
return dek, nil
}
// look up the kek used for this dek
kek, err := dec.keySource.GetKeyEncryptionKey(keyEncryptionKeyID)
if err != nil {
return nil, fmt.Errorf("protoutil: error getting key-encryption-key (%s): %w",
keyEncryptionKeyID, err)
}
// decrypt the dek via the private kek
dek, err = kek.DecryptDataEncryptionKey(encryptedDEK)
if err != nil {
return nil, fmt.Errorf("protoutil: error decrypting data-encryption-key: %w", err)
}
// cache it for next time
dec.dekCache.Put(encryptedDEK, dek)
return dek, nil
}
// Decrypt decrypts an encrypted protobuf message.
func (dec *Decryptor) Decrypt(src *cryptpb.SealedMessage) (proto.Message, error) {
dek, err := dec.getDataEncryptionKey(src.GetKeyId(), src.GetDataEncryptionKey())
if err != nil {
return nil, err
}
plaintext, err := dek.Decrypt(src.GetEncryptedMessage())
if err != nil {
return nil, err
}
msg, err := (&anypb.Any{TypeUrl: src.GetMessageType()}).UnmarshalNew()
if err != nil {
return nil, err
}
err = protojson.Unmarshal(plaintext, msg)
if err != nil {
return nil, err
}
return msg, nil
}

View file

@ -1,101 +0,0 @@
package protoutil
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/wrapperspb"
"github.com/pomerium/pomerium/pkg/cryptutil"
)
func TestEncryptor_Encrypt(t *testing.T) {
t.Run("simple", func(t *testing.T) {
kek, err := cryptutil.GenerateKeyEncryptionKey()
require.NoError(t, err)
enc := NewEncryptor(kek.Public())
sealed, err := enc.Encrypt(wrapperspb.String("HELLO WORLD"))
require.NoError(t, err)
require.Equal(t, kek.Public().ID(), sealed.GetKeyId())
require.NotEmpty(t, sealed.GetDataEncryptionKey())
require.Equal(t, "type.googleapis.com/google.protobuf.StringValue", sealed.GetMessageType())
require.NotEmpty(t, sealed.GetEncryptedMessage())
})
t.Run("reuse dek", func(t *testing.T) {
kek, err := cryptutil.GenerateKeyEncryptionKey()
require.NoError(t, err)
enc := NewEncryptor(kek.Public())
s1, err := enc.Encrypt(wrapperspb.String("HELLO WORLD"))
require.NoError(t, err)
s2, err := enc.Encrypt(wrapperspb.String("HELLO WORLD"))
require.NoError(t, err)
assert.Equal(t, s1.GetDataEncryptionKey(), s2.GetDataEncryptionKey())
})
t.Run("rotate dek", func(t *testing.T) {
kek, err := cryptutil.GenerateKeyEncryptionKey()
require.NoError(t, err)
enc := NewEncryptor(kek.Public())
s1, err := enc.Encrypt(wrapperspb.String("HELLO WORLD"))
require.NoError(t, err)
enc.nextRotate = time.Now()
s2, err := enc.Encrypt(wrapperspb.String("HELLO WORLD"))
require.NoError(t, err)
assert.NotEqual(t, s1.GetDataEncryptionKey(), s2.GetDataEncryptionKey())
})
}
func TestDecryptor_Decrypt(t *testing.T) {
expect := wrapperspb.String("HELLO WORLD")
kek, err := cryptutil.GenerateKeyEncryptionKey()
require.NoError(t, err)
enc := NewEncryptor(kek.Public())
sealed, err := enc.Encrypt(expect)
require.NoError(t, err)
dec := NewDecryptor(cryptutil.KeyEncryptionKeySourceFunc(func(id string) (*cryptutil.PrivateKeyEncryptionKey, error) {
require.Equal(t, kek.ID(), id)
return kek, nil
}))
opened, err := dec.Decrypt(sealed)
require.NoError(t, err)
assertProtoEqual(t, expect, opened)
}
func assertProtoEqual(t *testing.T, x, y proto.Message) {
xbs, _ := protojson.Marshal(x)
ybs, _ := protojson.Marshal(y)
assert.True(t, proto.Equal(x, y), "%s != %s", xbs, ybs)
}
func BenchmarkEncrypt(b *testing.B) {
m := map[string]any{}
for i := 0; i < 10; i++ {
mm := map[string]any{}
for j := 0; j < 10; j++ {
mm[fmt.Sprintf("key%d", j)] = fmt.Sprintf("value%d", j)
}
m[fmt.Sprintf("key%d", i)] = mm
}
obj, err := structpb.NewStruct(m)
require.NoError(b, err)
kek, err := cryptutil.GenerateKeyEncryptionKey()
require.NoError(b, err)
enc := NewEncryptor(kek.Public())
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := enc.Encrypt(obj)
require.NoError(b, err)
}
}