diff options
author | alexnick <alexnick@ydb.tech> | 2022-11-11 12:18:31 +0300 |
---|---|---|
committer | alexnick <alexnick@ydb.tech> | 2022-11-11 12:18:31 +0300 |
commit | 82bc476b6ce3ff9da9833655a60366aa80d8bbd8 (patch) | |
tree | 61d88e84cc303c6ff81f8485d42c3cbe6a47a4fa | |
parent | 093925786d1a146237d354b442f616e1b78d0156 (diff) | |
download | ydb-82bc476b6ce3ff9da9833655a60366aa80d8bbd8.tar.gz |
make ydb http proxy work with iam
-rw-r--r-- | ydb/apps/ydbd/main.cpp | 2 | ||||
-rw-r--r-- | ydb/core/http_proxy/CMakeLists.txt | 4 | ||||
-rw-r--r-- | ydb/core/http_proxy/auth_factory.cpp | 119 | ||||
-rw-r--r-- | ydb/core/http_proxy/auth_factory.h | 14 | ||||
-rw-r--r-- | ydb/core/http_proxy/http_req.cpp | 307 | ||||
-rw-r--r-- | ydb/core/http_proxy/http_req.h | 7 | ||||
-rw-r--r-- | ydb/public/sdk/cpp/client/CMakeLists.txt | 1 | ||||
-rw-r--r-- | ydb/public/sdk/cpp/client/iam_private/CMakeLists.txt | 19 | ||||
-rw-r--r-- | ydb/public/sdk/cpp/client/iam_private/iam.cpp | 28 | ||||
-rw-r--r-- | ydb/public/sdk/cpp/client/iam_private/iam.h | 13 | ||||
-rw-r--r-- | ydb/services/persqueue_v1/actors/persqueue_utils.h | 14 |
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 |