Skip to content

Commit 9b0f326

Browse files
authored
Merge 982f3dc into f322990
2 parents f322990 + 982f3dc commit 9b0f326

File tree

5 files changed

+142
-61
lines changed

5 files changed

+142
-61
lines changed

ydb/core/tx/schemeshard/schemeshard__operation.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ struct TSchemeShard::TTxOperationPropose: public NTabletFlatExecutor::TTransacti
346346
TProposeRequest::TPtr Request;
347347
THolder<TProposeResponse> Response = nullptr;
348348

349+
TString PeerName;
349350
TString UserSID;
350351
TString SanitizedToken;
351352

@@ -378,10 +379,12 @@ struct TSchemeShard::TTxOperationPropose: public NTabletFlatExecutor::TTransacti
378379
UserSID = userToken->GetUserSID();
379380
SanitizedToken = userToken->GetSanitizedToken();
380381
}
382+
PeerName = Request->Get()->Record.GetPeerName();
381383

382384
TMemoryChanges memChanges;
383385
TStorageChanges dbChanges;
384386
TOperationContext context{Self, txc, ctx, OnComplete, memChanges, dbChanges, std::move(userToken)};
387+
context.PeerName = PeerName;
385388

386389
//NOTE: Successful IgniteOperation will leave created operation in Self->Operations and accumulated changes in the context.
387390
// Unsuccessful IgniteOperation will leave no operation and context will also be clean.
@@ -444,7 +447,7 @@ struct TSchemeShard::TTxOperationPropose: public NTabletFlatExecutor::TTransacti
444447
<< ", response: " << Response->Record.ShortDebugString()
445448
<< ", at schemeshard: " << Self->TabletID());
446449

447-
AuditLogModifySchemeTransaction(record, Response->Record, Self, UserSID, SanitizedToken);
450+
AuditLogModifySchemeTransaction(record, Response->Record, Self, PeerName, UserSID, SanitizedToken);
448451

449452
//NOTE: Double audit output into the common log as a way to ease
450453
// transition to a new auditlog stream.

ydb/core/tx/schemeshard/schemeshard__operation_alter_login.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "schemeshard_audit_log.h"
12
#include "schemeshard__operation_part.h"
23
#include "schemeshard__operation_common.h"
34
#include "schemeshard_impl.h"
@@ -16,19 +17,24 @@ class TAlterLogin: public TSubOperationBase {
1617
THolder<TProposeResponse> Propose(const TString&, TOperationContext& context) override {
1718
NIceDb::TNiceDb db(context.GetTxc().DB); // do not track is there are direct writes happen
1819
TTabletId ssId = context.SS->SelfTabletId();
19-
auto result = MakeHolder<TProposeResponse>(OperationId.GetTxId(), ssId);
20+
const auto txId = OperationId.GetTxId();
21+
auto result = MakeHolder<TProposeResponse>(txId, ssId);
2022
if (!AppData()->AuthConfig.GetEnableLoginAuthentication()) {
2123
result->SetStatus(NKikimrScheme::StatusPreconditionFailed, "Login authentication is disabled");
2224
} else if (Transaction.GetWorkingDir() != context.SS->LoginProvider.Audience) {
2325
result->SetStatus(NKikimrScheme::StatusPreconditionFailed, "Wrong working dir");
2426
} else {
2527
const NKikimrConfig::TDomainsConfig::TSecurityConfig& securityConfig = context.SS->GetDomainsConfig().GetSecurityConfig();
2628
const NKikimrSchemeOp::TAlterLogin& alterLogin = Transaction.GetAlterLogin();
29+
30+
TParts additionalParts;
31+
2732
switch (alterLogin.GetAlterCase()) {
2833
case NKikimrSchemeOp::TAlterLogin::kCreateUser: {
2934
const auto& createUser = alterLogin.GetCreateUser();
3035
auto response = context.SS->LoginProvider.CreateUser(
3136
{.User = createUser.GetUser(), .Password = createUser.GetPassword()});
37+
3238
if (response.Error) {
3339
result->SetStatus(NKikimrScheme::StatusPreconditionFailed, response.Error);
3440
} else {
@@ -46,6 +52,8 @@ class TAlterLogin: public TSubOperationBase {
4652
}
4753
}
4854
result->SetStatus(NKikimrScheme::StatusSuccess);
55+
56+
AddIsUserAdmin(createUser.GetUser(), context.SS->LoginProvider, additionalParts);
4957
}
5058
break;
5159
}
@@ -58,16 +66,27 @@ class TAlterLogin: public TSubOperationBase {
5866
auto& sid = context.SS->LoginProvider.Sids[modifyUser.GetUser()];
5967
db.Table<Schema::LoginSids>().Key(sid.Name).Update<Schema::LoginSids::SidType, Schema::LoginSids::SidHash>(sid.Type, sid.Hash);
6068
result->SetStatus(NKikimrScheme::StatusSuccess);
69+
70+
AddIsUserAdmin(modifyUser.GetUser(), context.SS->LoginProvider, additionalParts);
71+
AddLastSuccessfulLogin(sid, additionalParts);
6172
}
6273
break;
6374
}
6475
case NKikimrSchemeOp::TAlterLogin::kRemoveUser: {
6576
const auto& removeUser = alterLogin.GetRemoveUser();
77+
78+
auto sid = context.SS->LoginProvider.Sids.find(removeUser.GetUser());
79+
if (context.SS->LoginProvider.Sids.end() != sid) {
80+
AddLastSuccessfulLogin(sid->second, additionalParts);
81+
}
82+
6683
auto response = RemoveUser(context, removeUser, db);
6784
if (response.Error) {
6885
result->SetStatus(NKikimrScheme::StatusPreconditionFailed, response.Error);
6986
} else {
7087
result->SetStatus(NKikimrScheme::StatusSuccess);
88+
89+
AddIsUserAdmin(removeUser.GetUser(), context.SS->LoginProvider, additionalParts);
7190
}
7291
break;
7392
}
@@ -162,6 +181,15 @@ class TAlterLogin: public TSubOperationBase {
162181
break;
163182
}
164183
}
184+
185+
TString userSID, sanitizedToken;
186+
if (context.UserToken) {
187+
userSID = context.UserToken->GetUserSID();
188+
sanitizedToken = context.UserToken->GetSanitizedToken();
189+
}
190+
const auto status = result->Record.GetStatus();
191+
const auto reason = result->Record.HasReason() ? result->Record.GetReason() : TString();
192+
AuditLogModifySchemeOperation(Transaction, status, reason, context.SS, context.PeerName, userSID, sanitizedToken, ui64(txId), additionalParts);
165193
}
166194

167195
if (result->Record.GetStatus() == NKikimrScheme::StatusSuccess) {
@@ -246,6 +274,30 @@ class TAlterLogin: public TSubOperationBase {
246274

247275
return {}; // success
248276
}
277+
278+
void AddIsUserAdmin(const TString& user, NLogin::TLoginProvider& loginProvider, TParts& additionalParts) {
279+
const auto& adminSids = AppData()->AdministrationAllowedSIDs;
280+
bool isAdmin = adminSids.empty();
281+
if (!isAdmin) {
282+
const auto providerGroups = loginProvider.GetGroupsMembership(user);
283+
const TVector<NACLib::TSID> groups(providerGroups.begin(), providerGroups.end());
284+
const auto userToken = NACLib::TUserToken(user, groups);
285+
auto hasSid = [&userToken](const TString& sid) -> bool {
286+
return userToken.IsExist(sid);
287+
};
288+
isAdmin = std::find_if(adminSids.begin(), adminSids.end(), hasSid) != adminSids.end();
289+
}
290+
291+
if (isAdmin) {
292+
additionalParts.emplace_back("login_user_level", "admin");
293+
}
294+
}
295+
296+
void AddLastSuccessfulLogin(NLogin::TLoginProvider::TSidRecord& sid, TParts& additionalParts) {
297+
if (sid.LastSuccessfulLogin) {
298+
additionalParts.emplace_back("last_login", TInstant::FromValue(sid.LastSuccessfulLogin).ToString());
299+
}
300+
}
249301
};
250302

251303
}

ydb/core/tx/schemeshard/schemeshard__operation_part.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct TOperationContext {
9595
TStorageChanges& DbChanges;
9696

9797
TMaybe<NACLib::TUserToken> UserToken;
98+
TString PeerName;
9899
bool IsAllowedPrivateTables = false;
99100

100101
private:

ydb/core/tx/schemeshard/schemeshard_audit_log.cpp

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include <ydb/library/actors/http/http.h>
77

8-
#include <ydb/core/protos/flat_tx_scheme.pb.h>
98
#include <ydb/core/protos/export.pb.h>
109
#include <ydb/core/protos/import.pb.h>
1110

@@ -81,57 +80,77 @@ TPath DatabasePathFromWorkingDir(TSchemeShard* SS, const TString &opWorkingDir)
8180

8281
} // anonymous namespace
8382

84-
void AuditLogModifySchemeTransaction(const NKikimrScheme::TEvModifySchemeTransaction& request, const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS, const TString& userSID, const TString& sanitizedToken) {
83+
void AuditLogModifySchemeOperation(const NKikimrSchemeOp::TModifyScheme& operation,
84+
NKikimrScheme::EStatus status, const TString& reason, TSchemeShard* SS,
85+
const TString& peerName, const TString& userSID, const TString& sanitizedToken,
86+
ui64 txId, const TParts& additionalParts) {
87+
auto logEntry = MakeAuditLogFragment(operation);
88+
89+
TPath databasePath = DatabasePathFromWorkingDir(SS, operation.GetWorkingDir());
90+
auto [cloud_id, folder_id, database_id] = GetDatabaseCloudIds(databasePath);
91+
auto address = NKikimr::NAddressClassifier::ExtractAddress(peerName);
92+
93+
AUDIT_LOG(
94+
AUDIT_PART("component", SchemeshardComponentName)
95+
AUDIT_PART("tx_id", std::to_string(txId))
96+
AUDIT_PART("remote_address", (!address.empty() ? address : EmptyValue))
97+
AUDIT_PART("subject", (!userSID.empty() ? userSID : EmptyValue))
98+
AUDIT_PART("sanitized_token", (!sanitizedToken.empty() ? sanitizedToken : EmptyValue))
99+
AUDIT_PART("database", (!databasePath.IsEmpty() ? databasePath.GetDomainPathString() : EmptyValue))
100+
AUDIT_PART("operation", logEntry.Operation)
101+
AUDIT_PART("paths", RenderList(logEntry.Paths), !logEntry.Paths.empty())
102+
AUDIT_PART("status", GeneralStatus(status))
103+
AUDIT_PART("detailed_status", NKikimrScheme::EStatus_Name(status))
104+
AUDIT_PART("reason", reason, !reason.empty())
105+
106+
for (const auto& [name, value] : additionalParts) {
107+
AUDIT_PART(name, (!value.empty() ? value : EmptyValue))
108+
}
109+
110+
AUDIT_PART("cloud_id", cloud_id, !cloud_id.empty());
111+
AUDIT_PART("folder_id", folder_id, !folder_id.empty());
112+
AUDIT_PART("resource_id", database_id, !database_id.empty());
113+
114+
// Additionally:
115+
116+
// ModifyACL.
117+
// Technically, non-empty ModifyACL field could come with any ModifyScheme operation.
118+
// In practice, ModifyACL will get processed only by:
119+
// 1. explicit operation ESchemeOpModifyACL -- to modify ACL on a path
120+
// 2. ESchemeOpMkDir or ESchemeOpCreate* operations -- to set rights to newly created paths/entities
121+
// 3. ESchemeOpCopyTable -- to be checked against acl size limit, not to be applied in any way
122+
AUDIT_PART("new_owner", logEntry.NewOwner, !logEntry.NewOwner.empty());
123+
AUDIT_PART("acl_add", RenderList(logEntry.ACLAdd), !logEntry.ACLAdd.empty());
124+
AUDIT_PART("acl_remove", RenderList(logEntry.ACLRemove), !logEntry.ACLRemove.empty());
125+
126+
// AlterUserAttributes.
127+
// 1. explicit operation ESchemeOpAlterUserAttributes -- to modify user attributes on a path
128+
// 2. ESchemeOpMkDir or some ESchemeOpCreate* operations -- to set user attributes for newly created paths/entities
129+
AUDIT_PART("user_attrs_add", RenderList(logEntry.UserAttrsAdd), !logEntry.UserAttrsAdd.empty());
130+
AUDIT_PART("user_attrs_remove", RenderList(logEntry.UserAttrsRemove), !logEntry.UserAttrsRemove.empty());
131+
132+
// AlterLogin.
133+
// explicit operation ESchemeOpAlterLogin -- to modify user and groups
134+
AUDIT_PART("login_user", logEntry.LoginUser);
135+
AUDIT_PART("login_group", logEntry.LoginGroup);
136+
AUDIT_PART("login_member", logEntry.LoginMember);
137+
);
138+
}
139+
140+
void AuditLogModifySchemeTransaction(const NKikimrScheme::TEvModifySchemeTransaction& request,
141+
const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS,
142+
const TString& peerName, const TString& userSID, const TString& sanitizedToken) {
85143
// Each TEvModifySchemeTransaction.Transaction is a self sufficient operation and should be logged independently
86144
// (even if it was packed into a single TxProxy transaction with some other operations).
145+
const auto txId = request.GetTxId();
146+
const auto status = response.GetStatus();
147+
const auto reason = response.HasReason() ? response.GetReason() : TString();
87148
for (const auto& operation : request.GetTransaction()) {
88-
auto logEntry = MakeAuditLogFragment(operation);
89-
90-
TPath databasePath = DatabasePathFromWorkingDir(SS, operation.GetWorkingDir());
91-
auto [cloud_id, folder_id, database_id] = GetDatabaseCloudIds(databasePath);
92-
auto peerName = NKikimr::NAddressClassifier::ExtractAddress(request.GetPeerName());
93-
94-
AUDIT_LOG(
95-
AUDIT_PART("component", SchemeshardComponentName)
96-
AUDIT_PART("tx_id", std::to_string(request.GetTxId()))
97-
AUDIT_PART("remote_address", (!peerName.empty() ? peerName : EmptyValue))
98-
AUDIT_PART("subject", (!userSID.empty() ? userSID : EmptyValue))
99-
AUDIT_PART("sanitized_token", (!sanitizedToken.empty() ? sanitizedToken : EmptyValue))
100-
AUDIT_PART("database", (!databasePath.IsEmpty() ? databasePath.GetDomainPathString() : EmptyValue))
101-
AUDIT_PART("operation", logEntry.Operation)
102-
AUDIT_PART("paths", RenderList(logEntry.Paths), !logEntry.Paths.empty())
103-
AUDIT_PART("status", GeneralStatus(response.GetStatus()))
104-
AUDIT_PART("detailed_status", NKikimrScheme::EStatus_Name(response.GetStatus()))
105-
AUDIT_PART("reason", response.GetReason(), response.HasReason())
106-
107-
AUDIT_PART("cloud_id", cloud_id, !cloud_id.empty());
108-
AUDIT_PART("folder_id", folder_id, !folder_id.empty());
109-
AUDIT_PART("resource_id", database_id, !database_id.empty());
110-
111-
// Additionally:
112-
113-
// ModifyACL.
114-
// Technically, non-empty ModifyACL field could come with any ModifyScheme operation.
115-
// In practice, ModifyACL will get processed only by:
116-
// 1. explicit operation ESchemeOpModifyACL -- to modify ACL on a path
117-
// 2. ESchemeOpMkDir or ESchemeOpCreate* operations -- to set rights to newly created paths/entities
118-
// 3. ESchemeOpCopyTable -- to be checked against acl size limit, not to be applied in any way
119-
AUDIT_PART("new_owner", logEntry.NewOwner, !logEntry.NewOwner.empty());
120-
AUDIT_PART("acl_add", RenderList(logEntry.ACLAdd), !logEntry.ACLAdd.empty());
121-
AUDIT_PART("acl_remove", RenderList(logEntry.ACLRemove), !logEntry.ACLRemove.empty());
122-
123-
// AlterUserAttributes.
124-
// 1. explicit operation ESchemeOpAlterUserAttributes -- to modify user attributes on a path
125-
// 2. ESchemeOpMkDir or some ESchemeOpCreate* operations -- to set user attributes for newly created paths/entities
126-
AUDIT_PART("user_attrs_add", RenderList(logEntry.UserAttrsAdd), !logEntry.UserAttrsAdd.empty());
127-
AUDIT_PART("user_attrs_remove", RenderList(logEntry.UserAttrsRemove), !logEntry.UserAttrsRemove.empty());
128-
129-
// AlterLogin.
130-
// explicit operation ESchemeOpAlterLogin -- to modify user and groups
131-
AUDIT_PART("login_user", logEntry.LoginUser);
132-
AUDIT_PART("login_group", logEntry.LoginGroup);
133-
AUDIT_PART("login_member", logEntry.LoginMember);
134-
);
149+
const auto type = operation.GetOperationType();
150+
if (NKikimrSchemeOp::EOperationType::ESchemeOpAlterLogin == type) {
151+
continue;
152+
}
153+
AuditLogModifySchemeOperation(operation, status, reason, SS, peerName, userSID, sanitizedToken, txId, TParts());
135154
}
136155
}
137156

@@ -194,7 +213,7 @@ struct TXxportRecord {
194213
TString Status;
195214
Ydb::StatusIds::StatusCode DetailedStatus;
196215
TString Reason;
197-
TVector<std::pair<TString, TString>> AdditionalParts;
216+
TParts AdditionalParts;
198217
TString StartTime;
199218
TString EndTime;
200219
TString CloudId;

ydb/core/tx/schemeshard/schemeshard_audit_log.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
#pragma once
22

33
#include <util/generic/string.h>
4-
5-
namespace NKikimrScheme {
6-
class TEvModifySchemeTransaction;
7-
class TEvModifySchemeTransactionResult;
8-
9-
class TEvLogin;
10-
class TEvLoginResult;
11-
}
4+
#include <ydb/core/protos/flat_tx_scheme.pb.h>
125

136
namespace NKikimrExport {
147
class TEvCreateExportRequest;
@@ -24,13 +17,26 @@ namespace NHttp {
2417
class THttpIncomingRequest;
2518
}
2619

20+
namespace NKikimrSchemeOp {
21+
class TModifyScheme;
22+
}
23+
2724
namespace NKikimr::NSchemeShard {
2825

2926
class TSchemeShard;
3027
struct TExportInfo;
3128
struct TImportInfo;
3229

33-
void AuditLogModifySchemeTransaction(const NKikimrScheme::TEvModifySchemeTransaction& request, const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS, const TString& userSID, const TString& sanitizedToken);
30+
using TParts = TVector<std::pair<TString, TString>>;
31+
32+
void AuditLogModifySchemeOperation(const NKikimrSchemeOp::TModifyScheme& operation,
33+
NKikimrScheme::EStatus status, const TString& reason, TSchemeShard* SS,
34+
const TString& peerName, const TString& userSID, const TString& sanitizedToken,
35+
ui64 txId, const TParts& additionalParts);
36+
37+
void AuditLogModifySchemeTransaction(const NKikimrScheme::TEvModifySchemeTransaction& request,
38+
const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS,
39+
const TString& peerName, const TString& userSID, const TString& sanitizedToken);
3440
void AuditLogModifySchemeTransactionDeprecated(const NKikimrScheme::TEvModifySchemeTransaction& request, const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS, const TString& userSID);
3541

3642
void AuditLogExportStart(const NKikimrExport::TEvCreateExportRequest& request, const NKikimrExport::TEvCreateExportResponse& response, TSchemeShard* SS);

0 commit comments

Comments
 (0)