Skip to content

Commit 6bd10ab

Browse files
authored
Merge 19c8b20 into ada1a64
2 parents ada1a64 + 19c8b20 commit 6bd10ab

File tree

5 files changed

+121
-52
lines changed

5 files changed

+121
-52
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: 35 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"
@@ -12,17 +13,37 @@ class TAlterLogin: public TSubOperationBase {
1213
public:
1314
using TSubOperationBase::TSubOperationBase;
1415

16+
void AddLastSuccessfulAttempt(const TString& user, NIceDb::TNiceDb& db, TParts& additionalParts) {
17+
static const TString LastSuccessfulAttemptAuditParam = "last_login";
18+
19+
auto row = db.Table<Schema::LoginSids>().Key(user).Select();
20+
if (!row.IsReady() || !row.IsValid()) {
21+
return;
22+
}
23+
24+
const auto time = TInstant::FromValue(row.GetValueOrDefault<Schema::LoginSids::LastSuccessfulAttempt>(0));
25+
if (!time) {
26+
return;
27+
}
28+
29+
additionalParts.emplace_back(LastSuccessfulAttemptAuditParam, time.ToString());
30+
}
31+
1532
THolder<TProposeResponse> Propose(const TString&, TOperationContext& context) override {
1633
NIceDb::TNiceDb db(context.GetTxc().DB); // do not track is there are direct writes happen
1734
TTabletId ssId = context.SS->SelfTabletId();
18-
auto result = MakeHolder<TProposeResponse>(OperationId.GetTxId(), ssId);
35+
const auto txId = OperationId.GetTxId();
36+
auto result = MakeHolder<TProposeResponse>(txId, ssId);
1937
if (!AppData()->AuthConfig.GetEnableLoginAuthentication()) {
2038
result->SetStatus(NKikimrScheme::StatusPreconditionFailed, "Login authentication is disabled");
2139
} else if (Transaction.GetWorkingDir() != context.SS->LoginProvider.Audience) {
2240
result->SetStatus(NKikimrScheme::StatusPreconditionFailed, "Wrong working dir");
2341
} else {
2442
const NKikimrConfig::TDomainsConfig::TSecurityConfig& securityConfig = context.SS->GetDomainsConfig().GetSecurityConfig();
2543
const NKikimrSchemeOp::TAlterLogin& alterLogin = Transaction.GetAlterLogin();
44+
45+
TParts additionalParts;
46+
2647
switch (alterLogin.GetAlterCase()) {
2748
case NKikimrSchemeOp::TAlterLogin::kCreateUser: {
2849
const auto& createUser = alterLogin.GetCreateUser();
@@ -48,6 +69,9 @@ class TAlterLogin: public TSubOperationBase {
4869
}
4970
case NKikimrSchemeOp::TAlterLogin::kModifyUser: {
5071
const auto& modifyUser = alterLogin.GetModifyUser();
72+
73+
AddLastSuccessfulAttempt(modifyUser.GetUser(), db, additionalParts);
74+
5175
auto response = context.SS->LoginProvider.ModifyUser({.User = modifyUser.GetUser(), .Password = modifyUser.GetPassword()});
5276
if (response.Error) {
5377
result->SetStatus(NKikimrScheme::StatusPreconditionFailed, response.Error);
@@ -60,6 +84,9 @@ class TAlterLogin: public TSubOperationBase {
6084
}
6185
case NKikimrSchemeOp::TAlterLogin::kRemoveUser: {
6286
const auto& removeUser = alterLogin.GetRemoveUser();
87+
88+
AddLastSuccessfulAttempt(removeUser.GetUser(), db, additionalParts);
89+
6390
auto response = RemoveUser(context, removeUser, db);
6491
if (response.Error) {
6592
result->SetStatus(NKikimrScheme::StatusPreconditionFailed, response.Error);
@@ -158,6 +185,13 @@ class TAlterLogin: public TSubOperationBase {
158185
break;
159186
}
160187
}
188+
189+
TString userSID, sanitizedToken;
190+
if (context.UserToken) {
191+
userSID = context.UserToken->GetUserSID();
192+
sanitizedToken = context.UserToken->GetSanitizedToken();
193+
}
194+
AuditLogModifySchemeTransaction(Transaction, result->Record, context.SS, context.PeerName, userSID, sanitizedToken, ui64(txId), additionalParts);
161195
}
162196

163197
if (result->Record.GetStatus() == NKikimrScheme::StatusSuccess) {

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: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -81,57 +81,75 @@ TPath DatabasePathFromWorkingDir(TSchemeShard* SS, const TString &opWorkingDir)
8181

8282
} // anonymous namespace
8383

84-
void AuditLogModifySchemeTransaction(const NKikimrScheme::TEvModifySchemeTransaction& request, const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS, const TString& userSID, const TString& sanitizedToken) {
84+
void AuditLogModifySchemeTransaction(const NKikimrSchemeOp::TModifyScheme& operation,
85+
const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS,
86+
const TString& peerName, const TString& userSID, const TString& sanitizedToken,
87+
ui64 txId, const TParts& additionalParts) {
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 address = NKikimr::NAddressClassifier::ExtractAddress(peerName);
93+
94+
AUDIT_LOG(
95+
AUDIT_PART("component", SchemeshardComponentName)
96+
AUDIT_PART("tx_id", std::to_string(txId))
97+
AUDIT_PART("remote_address", (!address.empty() ? address : 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+
for (const auto& [name, value] : additionalParts) {
108+
AUDIT_PART(name, (!value.empty() ? value : EmptyValue))
109+
}
110+
111+
AUDIT_PART("cloud_id", cloud_id, !cloud_id.empty());
112+
AUDIT_PART("folder_id", folder_id, !folder_id.empty());
113+
AUDIT_PART("resource_id", database_id, !database_id.empty());
114+
115+
// Additionally:
116+
117+
// ModifyACL.
118+
// Technically, non-empty ModifyACL field could come with any ModifyScheme operation.
119+
// In practice, ModifyACL will get processed only by:
120+
// 1. explicit operation ESchemeOpModifyACL -- to modify ACL on a path
121+
// 2. ESchemeOpMkDir or ESchemeOpCreate* operations -- to set rights to newly created paths/entities
122+
// 3. ESchemeOpCopyTable -- to be checked against acl size limit, not to be applied in any way
123+
AUDIT_PART("new_owner", logEntry.NewOwner, !logEntry.NewOwner.empty());
124+
AUDIT_PART("acl_add", RenderList(logEntry.ACLAdd), !logEntry.ACLAdd.empty());
125+
AUDIT_PART("acl_remove", RenderList(logEntry.ACLRemove), !logEntry.ACLRemove.empty());
126+
127+
// AlterUserAttributes.
128+
// 1. explicit operation ESchemeOpAlterUserAttributes -- to modify user attributes on a path
129+
// 2. ESchemeOpMkDir or some ESchemeOpCreate* operations -- to set user attributes for newly created paths/entities
130+
AUDIT_PART("user_attrs_add", RenderList(logEntry.UserAttrsAdd), !logEntry.UserAttrsAdd.empty());
131+
AUDIT_PART("user_attrs_remove", RenderList(logEntry.UserAttrsRemove), !logEntry.UserAttrsRemove.empty());
132+
133+
// AlterLogin.
134+
// explicit operation ESchemeOpAlterLogin -- to modify user and groups
135+
AUDIT_PART("login_user", logEntry.LoginUser);
136+
AUDIT_PART("login_group", logEntry.LoginGroup);
137+
AUDIT_PART("login_member", logEntry.LoginMember);
138+
);
139+
}
140+
141+
void AuditLogModifySchemeTransaction(const NKikimrScheme::TEvModifySchemeTransaction& request,
142+
const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS,
143+
const TString& peerName, const TString& userSID, const TString& sanitizedToken) {
85144
// Each TEvModifySchemeTransaction.Transaction is a self sufficient operation and should be logged independently
86145
// (even if it was packed into a single TxProxy transaction with some other operations).
146+
const auto txId = request.GetTxId();
87147
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-
);
148+
const auto type = operation.GetOperationType();
149+
if (NKikimrSchemeOp::EOperationType::ESchemeOpAlterLogin == type) {
150+
continue;
151+
}
152+
AuditLogModifySchemeTransaction(operation, response, SS, peerName, userSID, sanitizedToken, txId, TParts());
135153
}
136154
}
137155

@@ -194,7 +212,7 @@ struct TXxportRecord {
194212
TString Status;
195213
Ydb::StatusIds::StatusCode DetailedStatus;
196214
TString Reason;
197-
TVector<std::pair<TString, TString>> AdditionalParts;
215+
TParts AdditionalParts;
198216
TString StartTime;
199217
TString EndTime;
200218
TString CloudId;

ydb/core/tx/schemeshard/schemeshard_audit_log.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,26 @@ namespace NHttp {
2424
class THttpIncomingRequest;
2525
}
2626

27+
namespace NKikimrSchemeOp {
28+
class TModifyScheme;
29+
}
30+
2731
namespace NKikimr::NSchemeShard {
2832

2933
class TSchemeShard;
3034
struct TExportInfo;
3135
struct TImportInfo;
3236

33-
void AuditLogModifySchemeTransaction(const NKikimrScheme::TEvModifySchemeTransaction& request, const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS, const TString& userSID, const TString& sanitizedToken);
37+
using TParts = TVector<std::pair<TString, TString>>;
38+
39+
void AuditLogModifySchemeTransaction(const NKikimrSchemeOp::TModifyScheme& operation,
40+
const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS,
41+
const TString& peerName, const TString& userSID, const TString& sanitizedToken,
42+
ui64 txId, const TParts& additionalParts);
43+
44+
void AuditLogModifySchemeTransaction(const NKikimrScheme::TEvModifySchemeTransaction& request,
45+
const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS,
46+
const TString& peerName, const TString& userSID, const TString& sanitizedToken);
3447
void AuditLogModifySchemeTransactionDeprecated(const NKikimrScheme::TEvModifySchemeTransaction& request, const NKikimrScheme::TEvModifySchemeTransactionResult& response, TSchemeShard* SS, const TString& userSID);
3548

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

0 commit comments

Comments
 (0)