aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoralexnick <alexnick@ydb.tech>2022-11-11 12:18:31 +0300
committeralexnick <alexnick@ydb.tech>2022-11-11 12:18:31 +0300
commit82bc476b6ce3ff9da9833655a60366aa80d8bbd8 (patch)
tree61d88e84cc303c6ff81f8485d42c3cbe6a47a4fa
parent093925786d1a146237d354b442f616e1b78d0156 (diff)
downloadydb-82bc476b6ce3ff9da9833655a60366aa80d8bbd8.tar.gz
make ydb http proxy work with iam
-rw-r--r--ydb/apps/ydbd/main.cpp2
-rw-r--r--ydb/core/http_proxy/CMakeLists.txt4
-rw-r--r--ydb/core/http_proxy/auth_factory.cpp119
-rw-r--r--ydb/core/http_proxy/auth_factory.h14
-rw-r--r--ydb/core/http_proxy/http_req.cpp307
-rw-r--r--ydb/core/http_proxy/http_req.h7
-rw-r--r--ydb/public/sdk/cpp/client/CMakeLists.txt1
-rw-r--r--ydb/public/sdk/cpp/client/iam_private/CMakeLists.txt19
-rw-r--r--ydb/public/sdk/cpp/client/iam_private/iam.cpp28
-rw-r--r--ydb/public/sdk/cpp/client/iam_private/iam.h13
-rw-r--r--ydb/services/persqueue_v1/actors/persqueue_utils.h14
11 files changed, 478 insertions, 50 deletions
diff --git a/ydb/apps/ydbd/main.cpp b/ydb/apps/ydbd/main.cpp
index a280b024b08..3f24369b360 100644
--- a/ydb/apps/ydbd/main.cpp
+++ b/ydb/apps/ydbd/main.cpp
@@ -22,7 +22,7 @@ int main(int argc, char **argv) {
factories->YdbCredentialProviderFactory = NKikimr::CreateYdbCredentialsProviderFactory;
factories->IoContextFactory = std::make_shared<NKikimr::NPDisk::TIoContextFactoryOSS>();
factories->SqsAuthFactory = std::make_shared<NKikimr::NSQS::TAuthFactory>();
- factories->DataStreamsAuthFactory = std::make_shared<NKikimr::NHttpProxy::TAuthFactory>();
+ factories->DataStreamsAuthFactory = std::make_shared<NKikimr::NHttpProxy::TIamAuthFactory>();
factories->AdditionalComputationNodeFactories = { NYql::GetPgFactory() };
return ParameterizedMain(argc, argv, std::move(factories));
diff --git a/ydb/core/http_proxy/CMakeLists.txt b/ydb/core/http_proxy/CMakeLists.txt
index 45dbb3560a6..01d1e50a36a 100644
--- a/ydb/core/http_proxy/CMakeLists.txt
+++ b/ydb/core/http_proxy/CMakeLists.txt
@@ -24,11 +24,15 @@ target_link_libraries(ydb-core-http_proxy PUBLIC
yql-public-issue
library-http_proxy-authorization
library-http_proxy-error
+ library-ycloud-api
+ library-ycloud-impl
ydb-library-naming_conventions
cpp-client-ydb_datastreams
cpp-client-ydb_persqueue_core
client-ydb_persqueue_public-codecs
+ cpp-client-iam_private
ydb-services-datastreams
+ services-persqueue_v1-actors
)
target_sources(ydb-core-http_proxy PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/http_proxy/auth_factory.cpp
diff --git a/ydb/core/http_proxy/auth_factory.cpp b/ydb/core/http_proxy/auth_factory.cpp
index f00d79e50dc..5d7edb38a92 100644
--- a/ydb/core/http_proxy/auth_factory.cpp
+++ b/ydb/core/http_proxy/auth_factory.cpp
@@ -1,67 +1,94 @@
#include "auth_factory.h"
-#include "http_service.h"
#include "http_req.h"
-#include "metrics_actor.h"
-#include "discovery_actor.h"
+#include <ydb/core/http_proxy/http_service.h>
+#include <ydb/core/http_proxy/http_req.h>
+#include <ydb/core/http_proxy/metrics_actor.h>
+#include <ydb/core/http_proxy/discovery_actor.h>
+
+#include <ydb/public/sdk/cpp/client/iam_private/iam.h>
#include <library/cpp/actors/http/http_proxy.h>
namespace NKikimr::NHttpProxy {
-void TAuthFactory::Initialize(
+
+void TIamAuthFactory::InitTenantDiscovery(
+ NActors::TActorSystemSetup::TLocalServices&,
+ const TAppData&,
+ const THttpConfig&, ui16)
+{
+}
+
+void TIamAuthFactory::Initialize(
NActors::TActorSystemSetup::TLocalServices& localServices,
const TAppData& appData,
const THttpConfig& httpConfig,
const NKikimrConfig::TGRpcConfig& grpcConfig)
{
- if (httpConfig.GetEnabled()) {
- ui32 grpcPort = 0;
- TString CA;
- grpcPort = grpcConfig.GetPort();
- // bool secure = false;
- if (!grpcPort) {
- // secure = true;
- grpcPort = grpcConfig.GetSslPort();
- }
- CA = grpcConfig.HasPathToCaFile() ? grpcConfig.GetPathToCaFile() : grpcConfig.GetCA();
-
- NKikimrConfig::TServerlessProxyConfig config;
- config.MutableHttpConfig()->CopyFrom(httpConfig);
- config.SetCaCert(CA);
- if (httpConfig.GetYandexCloudServiceRegion().size() == 0) {
- ythrow yexception() << "YandexCloudServiceRegion must not be empty";
- }
-
- const NYdb::TCredentialsProviderPtr credentialsProvider = NYdb::CreateInsecureCredentialsProviderFactory()->CreateProvider();
-
- auto actor = NKikimr::NHttpProxy::CreateMetricsActor(NKikimr::NHttpProxy::TMetricsSettings{appData.Counters->GetSubgroup("counters", "http_proxy")});
- localServices.push_back(std::pair<TActorId, TActorSetupCmd>(
- NKikimr::NHttpProxy::MakeMetricsServiceID(),
- TActorSetupCmd(actor, TMailboxType::HTSwap, appData.UserPoolId)));
-
- NKikimr::NHttpProxy::THttpProxyConfig httpProxyConfig;
- httpProxyConfig.Config = config;
- httpProxyConfig.CredentialsProvider = credentialsProvider;
-
- actor = NKikimr::NHttpProxy::CreateHttpProxy(httpProxyConfig);
- localServices.push_back(std::pair<TActorId, TActorSetupCmd>(
- NKikimr::NHttpProxy::MakeHttpProxyID(),
- TActorSetupCmd(actor, TMailboxType::HTSwap, appData.UserPoolId)));
-
- actor = NHttp::CreateHttpProxy();
- localServices.push_back(std::pair<TActorId, TActorSetupCmd>(
- NKikimr::NHttpProxy::MakeHttpServerServiceID(),
- TActorSetupCmd(actor, TMailboxType::HTSwap, appData.UserPoolId)));
+ if (!httpConfig.GetEnabled()) {
+ return;
}
+ ui32 grpcPort = 0;
+ TString CA;
+ grpcPort = grpcConfig.GetPort();
+ if (!grpcPort) {
+ grpcPort = grpcConfig.GetSslPort();
+ }
+ CA = httpConfig.GetCA();
-
+ NKikimrConfig::TServerlessProxyConfig config;
+ config.MutableHttpConfig()->CopyFrom(httpConfig);
+ config.SetCaCert(CA);
+ if (httpConfig.GetYandexCloudServiceRegion().size() == 0) {
+ ythrow yexception() << "YandexCloudServiceRegion must not be empty";
+ }
+ IActor* actor = NKikimr::NHttpProxy::CreateAccessServiceActor(config);
+ localServices.push_back(std::pair<TActorId, TActorSetupCmd>(
+ NKikimr::NHttpProxy::MakeAccessServiceID(),
+ TActorSetupCmd(actor, TMailboxType::HTSwap, appData.UserPoolId)));
+
+ InitTenantDiscovery(localServices, appData, httpConfig, grpcPort);
+
+ const TString& jwtFilename = httpConfig.GetJwtFile();
+ TString iamExternalEndpoint = httpConfig.GetIamTokenServiceEndpoint();
+
+ const NYdb::TCredentialsProviderFactoryPtr credentialsProviderFactory = jwtFilename.empty()
+ ? NYdb::CreateInsecureCredentialsProviderFactory()
+ : NYdb::CreateIamJwtFileCredentialsProviderFactoryPrivate(
+ {{.Endpoint = iamExternalEndpoint}, jwtFilename} );
+ const NYdb::TCredentialsProviderPtr credentialsProvider = credentialsProviderFactory->CreateProvider();
+
+
+ actor = NKikimr::NHttpProxy::CreateIamTokenServiceActor(config);
+ localServices.push_back(std::pair<TActorId, TActorSetupCmd>(
+ NKikimr::NHttpProxy::MakeIamTokenServiceID(),
+ TActorSetupCmd(actor, TMailboxType::HTSwap, appData.UserPoolId)));
+
+ actor = NKikimr::NHttpProxy::CreateMetricsActor(NKikimr::NHttpProxy::TMetricsSettings{appData.Counters->GetSubgroup("counters", "http_proxy")});
+ localServices.push_back(std::pair<TActorId, TActorSetupCmd>(
+ NKikimr::NHttpProxy::MakeMetricsServiceID(),
+ TActorSetupCmd(actor, TMailboxType::HTSwap, appData.UserPoolId)));
+
+ NKikimr::NHttpProxy::THttpProxyConfig httpProxyConfig;
+ httpProxyConfig.Config = config;
+ httpProxyConfig.CredentialsProvider = credentialsProvider;
+ httpProxyConfig.UseSDK = UseSDK();
+
+ actor = NKikimr::NHttpProxy::CreateHttpProxy(httpProxyConfig);
+ localServices.push_back(std::pair<TActorId, TActorSetupCmd>(
+ NKikimr::NHttpProxy::MakeHttpProxyID(),
+ TActorSetupCmd(actor, TMailboxType::HTSwap, appData.UserPoolId)));
+
+ actor = NHttp::CreateHttpProxy();
+ localServices.push_back(std::pair<TActorId, TActorSetupCmd>(
+ NKikimr::NHttpProxy::MakeHttpServerServiceID(),
+ TActorSetupCmd(actor, TMailboxType::HTSwap, appData.UserPoolId)));
}
-NActors::IActor* TAuthFactory::CreateAuthActor(const TActorId, THttpRequestContext&, THolder<NKikimr::NSQS::TAwsRequestSignV4>&&) const
+NActors::IActor* TIamAuthFactory::CreateAuthActor(const TActorId sender, THttpRequestContext& context, THolder<NKikimr::NSQS::TAwsRequestSignV4>&& signature) const
{
- Y_FAIL("No signature support");
- return nullptr;
+ return CreateIamAuthActor(sender, context, std::move(signature));
}
diff --git a/ydb/core/http_proxy/auth_factory.h b/ydb/core/http_proxy/auth_factory.h
index fa79c73a6d3..3571f6d5344 100644
--- a/ydb/core/http_proxy/auth_factory.h
+++ b/ydb/core/http_proxy/auth_factory.h
@@ -3,10 +3,10 @@
#include "http_req.h"
#include <ydb/library/http_proxy/authorization/signature.h>
#include <ydb/core/base/appdata.h>
-#include <ydb/public/sdk/cpp/client/ydb_types/credentials/credentials.h>
namespace NKikimr::NHttpProxy {
+
class IAuthFactory {
public:
using THttpConfig = NKikimrConfig::THttpProxyConfig;
@@ -22,7 +22,10 @@ public:
virtual ~IAuthFactory() = default;
};
-class TAuthFactory : public IAuthFactory {
+
+class TIamAuthFactory : public IAuthFactory {
+ using THttpConfig = NKikimrConfig::THttpProxyConfig;
+
public:
void Initialize(
NActors::TActorSystemSetup::TLocalServices&,
@@ -31,6 +34,13 @@ public:
const NKikimrConfig::TGRpcConfig& grpcConfig) final;
NActors::IActor* CreateAuthActor(const TActorId sender, THttpRequestContext& context, THolder<NKikimr::NSQS::TAwsRequestSignV4>&& signature) const final;
+
+ virtual void InitTenantDiscovery(NActors::TActorSystemSetup::TLocalServices&,
+ const TAppData& appData,
+ const THttpConfig& config, ui16 grpcPort);
+
+ virtual bool UseSDK() const { return false; }
};
}
+
diff --git a/ydb/core/http_proxy/http_req.cpp b/ydb/core/http_proxy/http_req.cpp
index b20ec1b5e75..dbb2926d81e 100644
--- a/ydb/core/http_proxy/http_req.cpp
+++ b/ydb/core/http_proxy/http_req.cpp
@@ -8,16 +8,31 @@
#include <library/cpp/cgiparam/cgiparam.h>
#include <library/cpp/http/misc/parsed_request.h>
#include <library/cpp/http/server/response.h>
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_writer.h>
+#include <library/cpp/protobuf/json/json_output_create.h>
+#include <library/cpp/protobuf/json/proto2json.h>
+#include <library/cpp/protobuf/json/proto2json_printer.h>
+#include <library/cpp/uri/uri.h>
#include <ydb/core/base/appdata.h>
#include <ydb/core/grpc_caching/cached_grpc_request_actor.h>
#include <ydb/core/grpc_services/local_rpc/local_rpc.h>
#include <ydb/core/protos/serverless_proxy_config.pb.h>
#include <ydb/core/viewer/json/json.h>
+#include <ydb/core/base/ticket_parser.h>
+#include <ydb/core/base/path.h>
+#include <ydb/core/tx/scheme_board/cache.h>
#include <ydb/library/http_proxy/authorization/auth_helpers.h>
#include <ydb/library/http_proxy/error/error.h>
#include <ydb/library/yql/public/issue/yql_issue_message.h>
+#include <ydb/library/ycloud/api/access_service.h>
+#include <ydb/library/ycloud/api/iam_token_service.h>
+#include <ydb/library/ycloud/impl/grpc_service_cache.h>
+#include <ydb/library/ycloud/impl/access_service.h>
+#include <ydb/library/ycloud/impl/iam_token_service.h>
+#include <ydb/services/persqueue_v1/actors/persqueue_utils.h>
#include <ydb/public/sdk/cpp/client/ydb_datastreams/datastreams.h>
#include <ydb/public/sdk/cpp/client/ydb_persqueue_core/impl/common.h>
@@ -27,7 +42,6 @@
#include <ydb/services/datastreams/shard_iterator.h>
#include <ydb/services/lib/sharding/sharding.h>
-#include <library/cpp/uri/uri.h>
#include <util/generic/guid.h>
#include <util/stream/file.h>
@@ -786,4 +800,295 @@ namespace NKikimr::NHttpProxy {
"Unknown ContentType";
}
}
+
+ class THttpAuthActor : public NActors::TActorBootstrapped<THttpAuthActor> {
+ public:
+ using TBase = NActors::TActorBootstrapped<THttpAuthActor>;
+
+ THttpAuthActor(const TActorId sender, THttpRequestContext& context,
+ THolder<NKikimr::NSQS::TAwsRequestSignV4>&& signature)
+ : Sender(sender)
+ , Prefix(context.LogPrefix())
+ , ServiceAccountId(context.ServiceAccountId)
+ , ServiceAccountCredentialsProvider(context.ServiceAccountCredentialsProvider)
+ , RequestId(context.RequestId)
+ , Signature(std::move(signature))
+ , ServiceConfig(context.ServiceConfig)
+ , IamToken(context.IamToken)
+ , Authorize(!context.Driver)
+ , Database(context.DatabaseName)
+ , StreamName(context.StreamName)
+ {
+ }
+
+ TStringBuilder LogPrefix() const {
+ return TStringBuilder() << Prefix << " [auth] ";
+ }
+
+ private:
+ STFUNC(StateWork)
+ {
+ switch (ev->GetTypeRewrite()) {
+ HFunc(TEvTxProxySchemeCache::TEvNavigateKeySetResult, HandleCacheNavigateResponse);
+ HFunc(NCloud::TEvAccessService::TEvAuthenticateResponse, HandleAuthenticationResult);
+ HFunc(NCloud::TEvIamTokenService::TEvCreateResponse, HandleServiceAccountIamToken);
+ HFunc(TEvTicketParser::TEvAuthorizeTicketResult, HandleTicketParser);
+ HFunc(TEvents::TEvPoisonPill, HandlePoison);
+ default:
+ HandleUnexpectedEvent(ev, ctx);
+ break;
+ }
+ }
+
+ void SendDescribeRequest(const TActorContext& ctx) {
+ auto schemeCacheRequest = std::make_unique<NSchemeCache::TSchemeCacheNavigate>();
+ NSchemeCache::TSchemeCacheNavigate::TEntry entry;
+ entry.Path = NKikimr::SplitPath(Database);
+ entry.Operation = NSchemeCache::TSchemeCacheNavigate::OpPath;
+ entry.SyncVersion = false;
+ schemeCacheRequest->ResultSet.emplace_back(entry);
+ ctx.Send(MakeSchemeCacheID(), MakeHolder<TEvTxProxySchemeCache::TEvNavigateKeySet>(schemeCacheRequest.release()));
+ }
+
+ void HandleCacheNavigateResponse(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev, const TActorContext& ctx) {
+ const NSchemeCache::TSchemeCacheNavigate* navigate = ev->Get()->Request.Get();
+ if (navigate->ErrorCount) {
+ return ReplyWithError(ctx, NYdb::EStatus::SCHEME_ERROR, TStringBuilder() << "Database with path '" << Database << "' doesn't exists");
+ }
+ Y_VERIFY(navigate->ResultSet.size() == 1);
+ if (navigate->ResultSet.front().PQGroupInfo) {
+ const auto& description = navigate->ResultSet.front().PQGroupInfo->Description;
+ FolderId = description.GetPQTabletConfig().GetYcFolderId();
+ CloudId = description.GetPQTabletConfig().GetYcCloudId();
+ DatabaseId = description.GetPQTabletConfig().GetYdbDatabaseId();
+ }
+ for (const auto& attr : navigate->ResultSet.front().Attributes) {
+ if (attr.first == "folder_id") FolderId = attr.second;
+ if (attr.first == "cloud_id") CloudId = attr.second;
+ if (attr.first == "database_id") DatabaseId = attr.second;
+ }
+ SendAuthenticationRequest(ctx);
+ }
+
+ void HandlePoison(const TEvents::TEvPoisonPill::TPtr&, const TActorContext& ctx) {
+ TBase::Die(ctx);
+ }
+
+ void HandleTicketParser(const TEvTicketParser::TEvAuthorizeTicketResult::TPtr& ev, const TActorContext& ctx) {
+
+ if (ev->Get()->Error) {
+ return ReplyWithError(ctx, NYdb::EStatus::UNAUTHORIZED, ev->Get()->Error.Message);
+ };
+ ctx.Send(Sender, new TEvServerlessProxy::TEvToken(ev->Get()->Token->GetUserSID(), "", ev->Get()->SerializedToken));
+
+ LOG_SP_DEBUG_S(ctx, NKikimrServices::HTTP_PROXY, "Authorized successfully");
+
+ TBase::Die(ctx);
+ }
+
+ void SendAuthenticationRequest(const TActorContext& ctx) {
+ TInstant signedAt;
+ if (!Signature.Get() && IamToken.empty()) {
+ return ReplyWithError(ctx, NYdb::EStatus::UNAUTHORIZED,
+ "Neither Credentials nor IAM token was provided");
+ }
+ if (Signature) {
+ bool found = false;
+ for (auto& cr : ServiceConfig.GetHttpConfig().GetYandexCloudServiceRegion()) {
+ if (cr == Signature->GetRegion()) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return ReplyWithError(ctx, NYdb::EStatus::UNAUTHORIZED,
+ TStringBuilder() << "Wrong service region: got " << Signature->GetRegion() <<
+ " expected " << ServiceConfig.GetHttpConfig().GetYandexCloudServiceRegion(0));
+ }
+
+ if (!TInstant::TryParseIso8601(Signature->GetSigningTimestamp(), signedAt)) {
+ return ReplyWithError(ctx, NYdb::EStatus::BAD_REQUEST,
+ "Failed to parse Signature timestamp");
+ }
+ }
+
+
+ if (Authorize) {
+ auto entries = NKikimr::NGRpcProxy::V1::GetTicketParserEntries(DatabaseId, FolderId);
+ if (Signature.Get()) {
+ TEvTicketParser::TEvAuthorizeTicket::TAccessKeySignature signature;
+ signature.AccessKeyId = Signature->GetAccessKeyId();
+ signature.StringToSign = Signature->GetStringToSign();
+ signature.Signature = Signature->GetParsedSignature();
+ signature.Service = "kinesis";
+ signature.Region = Signature->GetRegion();
+ signature.SignedAt = signedAt;
+
+ THolder<TEvTicketParser::TEvAuthorizeTicket> request =
+ MakeHolder<TEvTicketParser::TEvAuthorizeTicket>(std::move(signature), "", entries);
+ ctx.Send(MakeTicketParserID(), request.Release());
+ } else {
+ THolder<TEvTicketParser::TEvAuthorizeTicket> request =
+ MakeHolder<TEvTicketParser::TEvAuthorizeTicket>(IamToken, "", entries);
+ ctx.Send(MakeTicketParserID(), request.Release());
+
+ }
+ return;
+ }
+
+ THolder<NCloud::TEvAccessService::TEvAuthenticateRequest> request =
+ MakeHolder<NCloud::TEvAccessService::TEvAuthenticateRequest>();
+ request->RequestId = RequestId;
+
+ auto& signature = *request->Request.mutable_signature();
+ signature.set_access_key_id(Signature->GetAccessKeyId());
+ signature.set_string_to_sign(Signature->GetStringToSign());
+ signature.set_signature(Signature->GetParsedSignature());
+
+ auto& v4params = *signature.mutable_v4_parameters();
+ v4params.set_service("kinesis");
+ v4params.set_region(Signature->GetRegion());
+
+ const ui64 nanos = signedAt.NanoSeconds();
+ const ui64 seconds = nanos / 1'000'000'000ull;
+ const ui64 nanos_left = nanos % 1'000'000'000ull;
+
+ v4params.mutable_signed_at()->set_seconds(seconds);
+ v4params.mutable_signed_at()->set_nanos(nanos_left);
+
+ ctx.Send(MakeAccessServiceID(), std::move(request));
+ }
+
+ void HandleUnexpectedEvent(const TAutoPtr<NActors::IEventHandle>& ev, const TActorContext& ctx) {
+ Y_UNUSED(ev, ctx);
+ }
+
+ void HandleAuthenticationResult(NCloud::TEvAccessService::TEvAuthenticateResponse::TPtr& ev,
+ const TActorContext& ctx) {
+ if (!ev->Get()->Status.Ok()) {
+ RetryCounter.Click();
+ LOG_SP_INFO_S(ctx, NKikimrServices::HTTP_PROXY, "retry #" << RetryCounter.AttempN() << "; " <<
+ "can not authenticate service account user: " << ev->Get()->Status.Msg);
+ if (RetryCounter.HasAttemps()) {
+ SendAuthenticationRequest(ctx);
+ return;
+ }
+ return ReplyWithError(ctx, NYdb::EStatus::UNAUTHORIZED, TStringBuilder() <<
+ "requestid " << RequestId << "; " <<
+ "can not authenticate service account user: " << ev->Get()->Status.Msg);
+ } else if (!ev->Get()->Response.subject().has_service_account()) {
+ return ReplyWithError(ctx, NYdb::EStatus::UNAUTHORIZED,
+ "(this error should not have been reached).");
+ }
+ RetryCounter.Void();
+
+ ServiceAccountId = ev->Get()->Response.subject().service_account().id();
+ LOG_SP_INFO_S(ctx, NKikimrServices::HTTP_PROXY, "authenticated to " << ServiceAccountId);
+ SendIamTokenRequest(ctx);
+ }
+
+ void SendIamTokenRequest(const TActorContext& ctx) {
+ auto request = MakeHolder<NCloud::TEvIamTokenService::TEvCreateForServiceAccountRequest>();
+ request->RequestId = RequestId;
+ request->Token = ServiceAccountCredentialsProvider->GetAuthInfo();
+ request->Request.set_service_account_id(ServiceAccountId);
+
+ ctx.Send(MakeIamTokenServiceID(), std::move(request));
+ }
+
+ void ReplyWithError(const TActorContext& ctx, NYdb::EStatus status, const TString& errorText) {
+ ctx.Send(Sender, new TEvServerlessProxy::TEvError(status, errorText));
+ TBase::Die(ctx);
+ }
+
+ void HandleServiceAccountIamToken(NCloud::TEvIamTokenService::TEvCreateResponse::TPtr& ev,
+ const TActorContext& ctx) {
+ if (!ev->Get()->Status.Ok()) {
+ RetryCounter.Click();
+ LOG_SP_INFO_S(ctx, NKikimrServices::HTTP_PROXY, "retry #" << RetryCounter.AttempN() << "; " <<
+ "IAM token issue error: " << ev->Get()->Status.Msg);
+
+ if (RetryCounter.HasAttemps()) {
+ SendIamTokenRequest(ctx);
+ return;
+ }
+ return ReplyWithError(ctx, NYdb::EStatus::UNAUTHORIZED, TStringBuilder() <<
+ "IAM token issue error: " << ev->Get()->Status.Msg);
+ }
+ RetryCounter.Void();
+
+ Y_VERIFY(!ev->Get()->Response.iam_token().empty());
+
+ ctx.Send(Sender,
+ new TEvServerlessProxy::TEvToken(ServiceAccountId, ev->Get()->Response.iam_token()));
+
+ LOG_SP_DEBUG_S(ctx, NKikimrServices::HTTP_PROXY, "IAM token generated");
+
+ TBase::Die(ctx);
+ }
+
+ public:
+ void Bootstrap(const TActorContext& ctx) {
+ TBase::Become(&THttpAuthActor::StateWork);
+
+ if (Authorize) {
+ SendDescribeRequest(ctx);
+ return;
+ }
+ if (ServiceAccountId.empty()) {
+ SendAuthenticationRequest(ctx);
+ } else {
+ SendIamTokenRequest(ctx);
+ }
+ }
+
+ private:
+ const TActorId Sender;
+ const TString Prefix;
+ TString ServiceAccountId;
+ std::shared_ptr<NYdb::ICredentialsProvider> ServiceAccountCredentialsProvider;
+ const TString RequestId;
+ THolder<NKikimr::NSQS::TAwsRequestSignV4> Signature;
+ TRetryCounter RetryCounter;
+ const NKikimrConfig::TServerlessProxyConfig& ServiceConfig;
+ TString IamToken;
+ bool Authorize;
+ TString FolderId;
+ TString CloudId;
+ TString DatabaseId;
+ TString Database;
+ TString StreamName;
+ };
+
+
+ NActors::IActor* CreateIamAuthActor(const TActorId sender, THttpRequestContext& context, THolder<NKikimr::NSQS::TAwsRequestSignV4>&& signature)
+ {
+ return new THttpAuthActor(sender, context, std::move(signature));
+ }
+
+
+ NActors::IActor* CreateIamTokenServiceActor(const NKikimrConfig::TServerlessProxyConfig& config)
+ {
+ NCloud::TIamTokenServiceSettings tsSettings;
+ tsSettings.Endpoint = config.GetHttpConfig().GetIamTokenServiceEndpoint();
+ if (config.GetCaCert()) {
+ TString certificate = TFileInput(config.GetCaCert()).ReadAll();
+ tsSettings.CertificateRootCA = certificate;
+ }
+ return NCloud::CreateIamTokenService(tsSettings);
+ }
+
+ NActors::IActor* CreateAccessServiceActor(const NKikimrConfig::TServerlessProxyConfig& config)
+ {
+ NCloud::TAccessServiceSettings asSettings;
+ asSettings.Endpoint = config.GetHttpConfig().GetAccessServiceEndpoint();
+
+ if (config.GetCaCert()) {
+ TString certificate = TFileInput(config.GetCaCert()).ReadAll();
+ asSettings.CertificateRootCA = certificate;
+ }
+ return NCloud::CreateAccessServiceWithCache(asSettings);
+ }
+
} // namespace NKikimr::NHttpProxy
+
diff --git a/ydb/core/http_proxy/http_req.h b/ydb/core/http_proxy/http_req.h
index 78cd5f77e28..8973107348a 100644
--- a/ydb/core/http_proxy/http_req.h
+++ b/ydb/core/http_proxy/http_req.h
@@ -18,6 +18,7 @@
#include <util/string/builder.h>
+
namespace NKikimr::NHttpProxy {
HttpCodes StatusToHttpCode(NYdb::EStatus status);
@@ -117,4 +118,10 @@ private:
THashMap<TString, THolder<IHttpRequestProcessor>> Name2Processor;
};
+NActors::IActor* CreateAccessServiceActor(const NKikimrConfig::TServerlessProxyConfig& config);
+NActors::IActor* CreateIamTokenServiceActor(const NKikimrConfig::TServerlessProxyConfig& config);
+NActors::IActor* CreateIamAuthActor(const TActorId sender, THttpRequestContext& context, THolder<NKikimr::NSQS::TAwsRequestSignV4>&& signature);
+
+
} // namespace NKinesis::NHttpProxy
+
diff --git a/ydb/public/sdk/cpp/client/CMakeLists.txt b/ydb/public/sdk/cpp/client/CMakeLists.txt
index af119021d57..8a2d3e5db57 100644
--- a/ydb/public/sdk/cpp/client/CMakeLists.txt
+++ b/ydb/public/sdk/cpp/client/CMakeLists.txt
@@ -9,6 +9,7 @@
add_subdirectory(draft)
add_subdirectory(extensions)
add_subdirectory(iam)
+add_subdirectory(iam_private)
add_subdirectory(impl)
add_subdirectory(resources)
add_subdirectory(ydb_common_client)
diff --git a/ydb/public/sdk/cpp/client/iam_private/CMakeLists.txt b/ydb/public/sdk/cpp/client/iam_private/CMakeLists.txt
new file mode 100644
index 00000000000..59a9b5347c1
--- /dev/null
+++ b/ydb/public/sdk/cpp/client/iam_private/CMakeLists.txt
@@ -0,0 +1,19 @@
+
+# This file was gererated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+
+add_library(cpp-client-iam_private)
+target_link_libraries(cpp-client-iam_private PUBLIC
+ contrib-libs-cxxsupp
+ yutil
+ client-yc_private-iam
+ client-iam-common
+)
+target_sources(cpp-client-iam_private PRIVATE
+ ${CMAKE_SOURCE_DIR}/ydb/public/sdk/cpp/client/iam_private/iam.cpp
+)
diff --git a/ydb/public/sdk/cpp/client/iam_private/iam.cpp b/ydb/public/sdk/cpp/client/iam_private/iam.cpp
new file mode 100644
index 00000000000..8eff5511a76
--- /dev/null
+++ b/ydb/public/sdk/cpp/client/iam_private/iam.cpp
@@ -0,0 +1,28 @@
+#include "iam.h"
+
+#include <ydb/public/sdk/cpp/client/iam/common/iam.h>
+
+#include <ydb/public/api/client/yc_private/iam/iam_token_service.pb.h>
+#include <ydb/public/api/client/yc_private/iam/iam_token_service.grpc.pb.h>
+
+namespace NYdb {
+
+TCredentialsProviderFactoryPtr CreateIamJwtCredentialsProviderFactoryImplPrivate(TIamJwtParams&& jwtParams) {
+ return std::make_shared<TIamJwtCredentialsProviderFactory<
+ yandex::cloud::priv::iam::v1::CreateIamTokenRequest,
+ yandex::cloud::priv::iam::v1::CreateIamTokenResponse,
+ yandex::cloud::priv::iam::v1::IamTokenService
+ >>(std::move(jwtParams));
+}
+
+TCredentialsProviderFactoryPtr CreateIamJwtFileCredentialsProviderFactoryPrivate(const TIamJwtFilename& params) {
+ TIamJwtParams jwtParams = { params, ReadJwtKeyFile(params.JwtFilename) };
+ return CreateIamJwtCredentialsProviderFactoryImplPrivate(std::move(jwtParams));
+}
+
+TCredentialsProviderFactoryPtr CreateIamJwtParamsCredentialsProviderFactoryPrivate(const TIamJwtContent& params) {
+ TIamJwtParams jwtParams = { params, ParseJwtParams(params.JwtContent) };
+ return CreateIamJwtCredentialsProviderFactoryImplPrivate(std::move(jwtParams));
+}
+
+}
diff --git a/ydb/public/sdk/cpp/client/iam_private/iam.h b/ydb/public/sdk/cpp/client/iam_private/iam.h
new file mode 100644
index 00000000000..508baec1e90
--- /dev/null
+++ b/ydb/public/sdk/cpp/client/iam_private/iam.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <ydb/public/sdk/cpp/client/iam/common/iam.h>
+
+namespace NYdb {
+
+/// Acquire an IAM token using a JSON Web Token (JWT) file name.
+TCredentialsProviderFactoryPtr CreateIamJwtFileCredentialsProviderFactoryPrivate(const TIamJwtFilename& params);
+
+/// Acquire an IAM token using JSON Web Token (JWT) contents.
+TCredentialsProviderFactoryPtr CreateIamJwtParamsCredentialsProviderFactoryPrivate(const TIamJwtContent& param);
+
+} // namespace NYdb
diff --git a/ydb/services/persqueue_v1/actors/persqueue_utils.h b/ydb/services/persqueue_v1/actors/persqueue_utils.h
index 6152f13d606..1442536e6bf 100644
--- a/ydb/services/persqueue_v1/actors/persqueue_utils.h
+++ b/ydb/services/persqueue_v1/actors/persqueue_utils.h
@@ -5,6 +5,7 @@
#include <ydb/library/aclib/aclib.h>
#include <ydb/core/scheme/scheme_tabledefs.h>
#include <ydb/core/base/counters.h>
+#include <ydb/core/base/ticket_parser.h>
#include <ydb/core/tx/scheme_cache/scheme_cache.h>
namespace NKikimr::NGRpcProxy::V1 {
@@ -70,4 +71,17 @@ static inline bool InternalErrorCode(Ydb::PersQueue::ErrorCode::ErrorCode errorC
void FillIssue(Ydb::Issue::IssueMessage* issue, const Ydb::PersQueue::ErrorCode::ErrorCode errorCode, const TString& errorReason);
+
+static inline TVector<TEvTicketParser::TEvAuthorizeTicket::TEntry> GetTicketParserEntries(const TString& dbId, const TString& folderId) {
+ static const TVector<TString> permissions = {"ydb.streams.write", "ydb.databases.list",
+ "ydb.databases.create", "ydb.databases.connect"};
+ TVector<std::pair<TString, TString>> attributes;
+ if (!dbId.empty()) attributes.push_back({"database_id", dbId});
+ if (!folderId.empty()) attributes.push_back({"folder_id", folderId});
+ if (!attributes.empty()) {
+ return {{permissions, attributes}};
+ }
+ return {};
+}
+
} //namespace NKikimr::NGRpcProxy::V1