Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 246 additions & 2 deletions ydb/core/grpc_services/base/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ using TYdbIssueMessageType = Ydb::Issue::IssueMessage;
std::pair<TString, TString> SplitPath(const TMaybe<TString>& database, const TString& path);
std::pair<TString, TString> SplitPath(const TString& path);

inline TActorId CreateGRpcRequestProxyId(int n = 0) {
if (n == 0) {
const auto actorId = TActorId(0, "GRpcReqProxy");
return actorId;
}

const auto actorId = TActorId(0, TStringBuilder() << "GRpcReqPro" << n);
return actorId;
}

struct TRpcServices {
enum EServiceId {
EvMakeDirectory = EventSpaceBegin(TKikimrEvents::ES_GRPC_CALLS),
Expand Down Expand Up @@ -224,7 +234,9 @@ struct TRpcServices {
EvAcquireYndxRateLimiterResource,
EvGrpcRuntimeRequest,
EvNodeCheckRequest,
EvStreamWriteRefreshToken // internal call, pair to EvRefreshToken
EvStreamWriteRefreshToken, // internal call, pair to EvRefreshToken
EvRequestAuthAndCheck, // performs authorization and runs GrpcRequestCheckActor
EvRequestAuthAndCheckResult,
// !!! DO NOT ADD NEW REQUEST !!!
};

Expand Down Expand Up @@ -365,7 +377,7 @@ class IRequestProxyCtx
virtual ~IRequestProxyCtx() = default;

// auth
virtual const TMaybe<TString> GetYdbToken() const = 0;
virtual const TMaybe<TString> GetYdbToken() const = 0;
virtual void UpdateAuthState(NYdbGrpc::TAuthState::EAuthState state) = 0;
virtual void SetInternalToken(const TIntrusiveConstPtr<NACLib::TUserToken>& token) = 0;
virtual const NYdbGrpc::TAuthState& GetAuthState() const = 0;
Expand Down Expand Up @@ -1553,5 +1565,237 @@ class TGRpcRequestValidationWrapper
bool RlAllowed;
};

class TEvRequestAuthAndCheckResult : public TEventLocal<TEvRequestAuthAndCheckResult, TRpcServices::EvRequestAuthAndCheckResult> {
public:
TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues)
: Status(status)
, Issues(issues)
{}

TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const NYql::TIssue& issue)
: Status(status)
{
Issues.AddIssue(issue);
}

TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const TString& error)
: Status(status)
{
Issues.AddIssue(error);
}

TEvRequestAuthAndCheckResult(const TString& database, const TMaybe<TString>& ydbToken, const TIntrusiveConstPtr<NACLib::TUserToken>& userToken)
: Database(database)
, YdbToken(ydbToken)
, UserToken(userToken)
{}

Ydb::StatusIds::StatusCode Status = Ydb::StatusIds::SUCCESS;
NYql::TIssues Issues;
TString Database;
TMaybe<TString> YdbToken;
TIntrusiveConstPtr<NACLib::TUserToken> UserToken;
};

class TEvRequestAuthAndCheck
: public IRequestProxyCtx
, public TEventLocal<TEvRequestAuthAndCheck, TRpcServices::EvRequestAuthAndCheck> {
public:
TEvRequestAuthAndCheck(const TString& database, const TMaybe<TString>& ydbToken, NActors::TActorId sender)
: Database(database)
, YdbToken(ydbToken)
, Sender(sender)
, AuthState(true)
{}

// IRequestProxyCtx
const TMaybe<TString> GetYdbToken() const override {
return YdbToken;
}

void UpdateAuthState(NYdbGrpc::TAuthState::EAuthState state) override {
AuthState.State = state;
}

void SetInternalToken(const TIntrusiveConstPtr<NACLib::TUserToken>& token) override {
UserToken = token;
}

const NYdbGrpc::TAuthState& GetAuthState() const override {
return AuthState;
}

void ReplyUnauthenticated(const TString& msg = "") override {
if (msg) {
IssueManager.RaiseIssue(NYql::TIssue{msg});
}
ReplyWithYdbStatus(Ydb::StatusIds::UNAUTHORIZED);
}

void ReplyWithYdbStatus(Ydb::StatusIds::StatusCode status) override {
const NActors::TActorContext& ctx = NActors::TActivationContext::AsActorContext();
if (status == Ydb::StatusIds::SUCCESS) {
ctx.Send(Sender,
new TEvRequestAuthAndCheckResult(
Database,
YdbToken,
UserToken
)
);
} else {
ctx.Send(Sender,
new TEvRequestAuthAndCheckResult(
status,
IssueManager.GetIssues()
)
);
}
}

void RaiseIssue(const NYql::TIssue& issue) override {
IssueManager.RaiseIssue(issue);
}

void RaiseIssues(const NYql::TIssues& issues) override {
IssueManager.RaiseIssues(issues);
}

TVector<TStringBuf> FindClientCertPropertyValues() const override {
return {};
}

void StartTracing(NWilson::TSpan&& span) override {
Span = std::move(span);
}
void FinishSpan() override {
Span.End();
}

bool* IsTracingDecided() override {
return nullptr;
}

bool Validate(TString& /*error*/) override {
return true;
}

void SetCounters(IGRpcProxyCounters::TPtr counters) override {
Counters = std::move(counters);
}

IGRpcProxyCounters::TPtr GetCounters() const override {
return Counters;
}

void UseDatabase(const TString& database) override {
Database = database;
}

void SetRespHook(TRespHook&& /*hook*/) override {
}

void SetRlPath(TMaybe<NRpcService::TRlPath>&& path) override {
RlPath = std::move(path);
}

TRateLimiterMode GetRlMode() const override {
return TRateLimiterMode::Rps;
}

bool TryCustomAttributeProcess(const TSchemeBoardEvents::TDescribeSchemeResult& /*schemeData*/, ICheckerIface* /*iface*/) override {
return false;
}

void Pass(const IFacilityProvider& /*facility*/) override {
ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
}

void SetAuditLogHook(TAuditLogHook&& /*hook*/) override {
}

void SetDiskQuotaExceeded(bool /*disk*/) override {
}

void AddAuditLogPart(const TStringBuf& name, const TString& value) override {
AuditLogParts.emplace_back(name, value);
}

const TAuditLogParts& GetAuditLogParts() const override {
return AuditLogParts;
}

TMaybe<TString> GetTraceId() const override {
return {};
}

NWilson::TTraceId GetWilsonTraceId() const override {
return Span.GetTraceId();
}

const TMaybe<TString> GetDatabaseName() const override {
return Database ? TMaybe<TString>(Database) : Nothing();
}

const TIntrusiveConstPtr<NACLib::TUserToken>& GetInternalToken() const override {
return UserToken;
}

const TString& GetSerializedToken() const override {
if (UserToken) {
return UserToken->GetSerializedToken();
}

return EmptySerializedTokenMessage;
}

bool IsClientLost() const override {
return false;
}

const TMaybe<TString> GetPeerMetaValues(const TString&) const override {
return {};
}

TString GetPeerName() const override {
return {};
}

const TString& GetRequestName() const override {
static TString str = "request auth and check internal request";
return str;
}

TMaybe<NRpcService::TRlPath> GetRlPath() const override {
return RlPath;
}

TInstant GetDeadline() const override {
return deadline;
}


TMaybe<TString> GetSdkBuildInfo() const {
return {};
}

TMaybe<TString> GetGrpcUserAgent() const {
return {};
}

TString Database;
TMaybe<TString> YdbToken;
NActors::TActorId Sender;
NYdbGrpc::TAuthState AuthState;
NWilson::TSpan Span;
IGRpcProxyCounters::TPtr Counters;
TMaybe<NRpcService::TRlPath> RlPath;
TAuditLogParts AuditLogParts;
NYql::TIssueManager IssueManager;
TIntrusiveConstPtr<NACLib::TUserToken> UserToken;
TInstant deadline = TInstant::Now() + TDuration::Seconds(10);

inline static const TString EmptySerializedTokenMessage;
};

} // namespace NGRpcService
} // namespace NKikimr
34 changes: 32 additions & 2 deletions ydb/core/grpc_services/grpc_request_check_actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ bool TGRpcRequestProxyHandleMethods::ValidateAndReplyOnError(TCtx* ctx) {
}
}

inline const TVector<TEvTicketParser::TEvAuthorizeTicket::TEntry>& GetEntriesForAuthAndCheckRequest(TEvRequestAuthAndCheck::TPtr& ev) {
if (ev->Get()->YdbToken && ev->Get()->YdbToken->StartsWith("Bearer")) {
if (AppData()->AuthConfig.GetUseAccessService()
&& (AppData()->DomainsConfig.GetSecurityConfig().ViewerAllowedSIDsSize() > 0 || AppData()->DomainsConfig.GetSecurityConfig().MonitoringAllowedSIDsSize() > 0)) {
static TVector<NKikimr::TEvTicketParser::TEvAuthorizeTicket::TEntry> entries = {
{NKikimr::TEvTicketParser::TEvAuthorizeTicket::ToPermissions({"ydb.developerApi.get", "ydb.developerApi.update"}), {{"gizmo_id", "gizmo"}}}
};
return entries;
}
}
static TVector<NKikimr::TEvTicketParser::TEvAuthorizeTicket::TEntry> emptyEntries = {};
return emptyEntries;
}

template <typename TEvent>
class TGrpcRequestCheckActor
: public TGRpcRequestProxyHandleMethods
Expand Down Expand Up @@ -73,7 +87,8 @@ class TGrpcRequestCheckActor
}

void ProcessCommonAttributes(const TSchemeBoardEvents::TDescribeSchemeResult& schemeData) {
static std::vector<TString> allowedAttributes = {"folder_id", "service_account_id", "database_id", "container_id"};
TVector<TEvTicketParser::TEvAuthorizeTicket::TEntry> entries;
static std::vector<TString> allowedAttributes = {"folder_id", "service_account_id", "database_id"};
TVector<std::pair<TString, TString>> attributes;
attributes.reserve(schemeData.GetPathDescription().UserAttributesSize());
for (const auto& attr : schemeData.GetPathDescription().GetUserAttributes()) {
Expand All @@ -82,7 +97,16 @@ class TGrpcRequestCheckActor
}
}
if (!attributes.empty()) {
SetEntries({{GetPermissions(), attributes}});
entries.emplace_back(GetPermissions(), attributes);
}

if constexpr (std::is_same_v<TEvent, TEvRequestAuthAndCheck>) {
const auto& e = GetEntriesForAuthAndCheckRequest(Request_);
entries.insert(entries.end(), e.begin(), e.end());
}

if (!entries.empty()) {
SetEntries(entries);
}
}

Expand Down Expand Up @@ -464,6 +488,12 @@ class TGrpcRequestCheckActor
ReplyBackAndDie();
}

void HandleAndDie(TEvRequestAuthAndCheck::TPtr& ev) {
GrpcRequestBaseCtx_->FinishSpan();
ev->Get()->ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
PassAway();
}

template <typename T>
void HandleAndDie(T& event) {
GrpcRequestBaseCtx_->FinishSpan();
Expand Down
8 changes: 7 additions & 1 deletion ydb/core/grpc_services/grpc_request_proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ class TGRpcRequestProxyImpl
NYql::TIssues()});
}

void Handle(TEvRequestAuthAndCheck::TPtr& ev, const TActorContext&) {
ev->Get()->FinishSpan();
ev->Get()->ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
}

// returns true and defer event if no updates for given database
// otherwice returns false and leave event untouched
template <typename TEvent>
Expand Down Expand Up @@ -186,7 +191,7 @@ class TGRpcRequestProxyImpl
if (maybeDatabaseName && !maybeDatabaseName.GetRef().empty()) {
databaseName = CanonizePath(maybeDatabaseName.GetRef());
} else {
if (!AllowYdbRequestsWithoutDatabase && DynamicNode) {
if (!AllowYdbRequestsWithoutDatabase && DynamicNode && !std::is_same_v<TEvent, TEvRequestAuthAndCheck>) { // TEvRequestAuthAndCheck is allowed to be processed without database
requestBaseCtx->ReplyUnauthenticated("Requests without specified database are not allowed");
requestBaseCtx->FinishSpan();
return;
Expand Down Expand Up @@ -590,6 +595,7 @@ void TGRpcRequestProxyImpl::StateFunc(TAutoPtr<IEventHandle>& ev) {
HFunc(TEvCoordinationSessionRequest, PreHandle);
HFunc(TEvNodeCheckRequest, PreHandle);
HFunc(TEvProxyRuntimeEvent, PreHandle);
HFunc(TEvRequestAuthAndCheck, PreHandle);

default:
Y_ABORT("Unknown request: %u\n", ev->GetTypeRewrite());
Expand Down
10 changes: 0 additions & 10 deletions ydb/core/grpc_services/grpc_request_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,5 @@ class TGRpcRequestProxy : public TGRpcRequestProxyHandleMethods, public IFacilit
TActorId DiscoveryCacheActorID;
};

inline TActorId CreateGRpcRequestProxyId(int n = 0) {
if (n == 0) {
const auto actorId = TActorId(0, "GRpcReqProxy");
return actorId;
}

const auto actorId = TActorId(0, TStringBuilder() << "GRpcReqPro" << n);
return actorId;
}

} // namespace NGRpcService
} // namespace NKikimr
Loading