Skip to content

Commit ca6fa08

Browse files
authored
Merge 65bacce into a92607e
2 parents a92607e + 65bacce commit ca6fa08

File tree

23 files changed

+629
-150
lines changed

23 files changed

+629
-150
lines changed

ydb/core/config/init/init.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ class TDefaultNodeBrokerClient
228228
const TGrpcSslSettings& grpcSettings,
229229
const TString addr,
230230
const NYdb::NDiscovery::TNodeRegistrationSettings& settings,
231+
const TString& nodeRegistrationToken,
231232
const IEnv& env)
232233
{
233234
TCommandConfig::TServerEndpoint endpoint = TCommandConfig::ParseServerAddress(addr);
@@ -242,7 +243,9 @@ class TDefaultNodeBrokerClient
242243
config.UseClientCertificate(certificate.c_str(), privateKey.c_str());
243244
}
244245
}
245-
config.SetAuthToken(BUILTIN_ACL_ROOT);
246+
if (nodeRegistrationToken) {
247+
config.SetAuthToken(nodeRegistrationToken);
248+
}
246249
config.SetEndpoint(endpoint.Address);
247250
auto connection = NYdb::TDriver(config);
248251

@@ -313,6 +316,7 @@ class TDefaultNodeBrokerClient
313316
const TGrpcSslSettings& grpcSettings,
314317
const TVector<TString>& addrs,
315318
const NYdb::NDiscovery::TNodeRegistrationSettings& settings,
319+
const TString& nodeRegistrationToken,
316320
const IEnv& env,
317321
IInitLogger& logger)
318322
{
@@ -326,6 +330,7 @@ class TDefaultNodeBrokerClient
326330
grpcSettings,
327331
addr,
328332
settings,
333+
nodeRegistrationToken,
329334
env);
330335
if (result.IsSuccess()) {
331336
logger.Out() << "Success. Registered via discovery service as " << result.GetNodeId() << Endl;
@@ -387,6 +392,7 @@ class TDefaultNodeBrokerClient
387392
grpcSettings,
388393
addrs,
389394
newRegSettings,
395+
regSettings.NodeRegistrationToken,
390396
env,
391397
logger);
392398

ydb/core/config/init/init.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ struct TNodeRegistrationSettings {
118118
bool FixedNodeID;
119119
ui32 InterconnectPort;
120120
NActors::TNodeLocation Location;
121+
TString NodeRegistrationToken;
121122
};
122123

123124
class INodeRegistrationResult {

ydb/core/config/init/init_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,7 @@ class TInitialConfiguratorImpl
12471247
cf.FixedNodeID,
12481248
cf.InterconnectPort,
12491249
cf.CreateNodeLocation(),
1250+
AppConfig.GetAuthConfig().GetNodeRegistrationToken(),
12501251
};
12511252

12521253
auto result = NodeBrokerClient.RegisterDynamicNode(cf.GrpcSslSettings, addrs, settings, Env, Logger);

ydb/core/driver_lib/run/kikimr_services_initializers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,7 @@ void TSecurityServicesInitializer::InitializeServices(NActors::TActorSystemSetup
16461646
.AuthConfig = Config.GetAuthConfig(),
16471647
.CertificateAuthValues = {
16481648
.ClientCertificateAuthorization = Config.GetClientCertificateAuthorization(),
1649-
.ServerCertificateFilePath = grpcConfig.GetCert(),
1649+
.ServerCertificateFilePath = grpcConfig.HasPathToCertificateFile() ? grpcConfig.GetPathToCertificateFile() : grpcConfig.GetCert(),
16501650
.Domain = Config.GetAuthConfig().GetCertificateAuthenticationDomain()
16511651
}
16521652
};

ydb/core/grpc_services/grpc_request_proxy.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,22 @@ void TGRpcRequestProxyImpl::HandleUndelivery(TEvents::TEvUndelivered::TPtr& ev)
420420

421421
bool TGRpcRequestProxyImpl::IsAuthStateOK(const IRequestProxyCtx& ctx) {
422422
const auto& state = ctx.GetAuthState();
423-
return state.State == NYdbGrpc::TAuthState::AS_OK ||
424-
state.State == NYdbGrpc::TAuthState::AS_FAIL && state.NeedAuth == false ||
425-
state.NeedAuth == false && !ctx.GetYdbToken();
423+
if (state.State == NYdbGrpc::TAuthState::AS_OK) {
424+
return true;
425+
}
426+
427+
const bool authorizationParamsAreSet = ctx.GetYdbToken() || !ctx.FindClientCertPropertyValues().empty();
428+
if (!state.NeedAuth && !authorizationParamsAreSet) {
429+
return true;
430+
}
431+
432+
if (!state.NeedAuth && state.State == NYdbGrpc::TAuthState::AS_FAIL) {
433+
if (AppData()->EnforceUserTokenCheckRequirement && authorizationParamsAreSet) {
434+
return false;
435+
}
436+
return true;
437+
}
438+
return false;
426439
}
427440

428441
void TGRpcRequestProxyImpl::MaybeStartTracing(IRequestProxyCtx& ctx) {

ydb/core/grpc_services/grpc_request_proxy_simple.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,22 @@ void TGRpcRequestProxySimple::HandleUndelivery(TEvents::TEvUndelivered::TPtr& ev
172172

173173
bool TGRpcRequestProxySimple::IsAuthStateOK(const IRequestProxyCtx& ctx) {
174174
const auto& state = ctx.GetAuthState();
175-
return state.State == NYdbGrpc::TAuthState::AS_OK ||
176-
state.State == NYdbGrpc::TAuthState::AS_FAIL && state.NeedAuth == false ||
177-
state.NeedAuth == false && !ctx.GetYdbToken();
175+
if (state.State == NYdbGrpc::TAuthState::AS_OK) {
176+
return true;
177+
}
178+
179+
const bool authorizationParamsAreSet = ctx.GetYdbToken() || !ctx.FindClientCertPropertyValues().empty();
180+
if (!state.NeedAuth && !authorizationParamsAreSet) {
181+
return true;
182+
}
183+
184+
if (!state.NeedAuth && state.State == NYdbGrpc::TAuthState::AS_FAIL) {
185+
if (AppData()->EnforceUserTokenCheckRequirement && authorizationParamsAreSet) {
186+
return false;
187+
}
188+
return true;
189+
}
190+
return false;
178191
}
179192

180193
template<typename TEvent>

ydb/core/grpc_services/rpc_whoami.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,29 @@ class TWhoAmIRPC : public TActorBootstrapped<TWhoAmIRPC> {
2121
: Request(request)
2222
{}
2323

24-
void Bootstrap(const TActorContext& ctx) {
24+
void Bootstrap() {
2525
//TODO: Do we realy realy need to make call to the ticket parser here???
2626
//we have done it already in grpc_request_proxy
2727
auto req = dynamic_cast<TEvWhoAmIRequest*>(Request.get());
2828
Y_ABORT_UNLESS(req, "Unexpected request type for TWhoAmIRPC");
29-
TMaybe<TString> authToken = req->GetYdbToken();
30-
if (authToken) {
31-
TMaybe<TString> database = Request->GetDatabaseName();
32-
ctx.Send(MakeTicketParserID(), new TEvTicketParser::TEvAuthorizeTicket({
33-
.Database = database ? database.GetRef() : TString(),
34-
.Ticket = authToken.GetRef(),
35-
.PeerName = Request->GetPeerName()
36-
}));
37-
Become(&TThis::StateWaitForTicket);
29+
TString ticket;
30+
if (TMaybe<TString> authToken = req->GetYdbToken()) {
31+
ticket = authToken.GetRef();
32+
} else if (TVector<TStringBuf> clientCert = Request->FindClientCert(); !clientCert.empty()) {
33+
ticket = TString(clientCert.front());
3834
} else {
3935
ReplyError("No token provided");
4036
PassAway();
37+
return;
4138
}
39+
40+
TMaybe<TString> database = Request->GetDatabaseName();
41+
Send(MakeTicketParserID(), new TEvTicketParser::TEvAuthorizeTicket({
42+
.Database = database ? database.GetRef() : TString(),
43+
.Ticket = ticket,
44+
.PeerName = Request->GetPeerName()
45+
}));
46+
Become(&TThis::StateWaitForTicket);
4247
}
4348

4449
STFUNC(StateWaitForTicket) {

ydb/core/protos/auth.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ message TAuthConfig {
5555
optional string AccessServiceType = 79 [default = "Yandex_v2"]; // For now the following values are supported: "Yandex_v2", "Nebius_v1"
5656
optional string CertificateAuthenticationDomain = 80 [default = "cert"];
5757
optional bool EnableLoginAuthentication = 81 [default = true];
58+
optional string NodeRegistrationToken = 82 [default = "root@builtin", (Ydb.sensitive) = true];
5859
}
5960

6061
message TUserRegistryConfig {

ydb/core/protos/config.proto

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,8 +1785,15 @@ message TClientCertificateAuthorization {
17851785
repeated string Suffixes = 3;
17861786
}
17871787

1788+
// Matches subject alternative names (DNS) and Common Name (CN) in certificate
1789+
message TSubjectDns {
1790+
repeated string Values = 1;
1791+
repeated string Suffixes = 2;
1792+
}
1793+
17881794
message TClientCertificateDefinition {
17891795
repeated TSubjectTerm SubjectTerms = 1;
1796+
optional TSubjectDns SubjectDns = 5;
17901797
optional bool CanCheckNodeHostByCN = 2 [default = false];
17911798
repeated string MemberGroups = 3;
17921799
optional bool RequireSameIssuer = 4 [default = true];

ydb/core/security/certificate_check/cert_auth_processor.cpp

Lines changed: 100 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "cert_auth_processor.h"
22

33
#include <openssl/x509.h>
4+
#include <openssl/x509v3.h>
45
#include <openssl/pem.h>
56
#include <openssl/bio.h>
67
#include <openssl/objects.h>
@@ -100,6 +101,56 @@ TVector<std::pair<TString, TString>> X509CertificateReader::ReadIssuerTerms(cons
100101
return ReadTerms(name);
101102
}
102103

104+
static void FreeList(GENERAL_NAMES* list) {
105+
sk_GENERAL_NAME_pop_free(list, GENERAL_NAME_free);
106+
}
107+
108+
TVector<TString> X509CertificateReader::ReadSubjectDns(const X509Ptr& x509, const std::vector<std::pair<TString, TString>>& subjectTerms) {
109+
TVector<TString> result;
110+
// 1. Subject's common name (CN) must be a subject DNS name, so add it to DNS names of subject first
111+
for (const auto& [k, v] : subjectTerms) {
112+
if (k == "CN") {
113+
result.emplace_back(v);
114+
}
115+
}
116+
117+
using TGeneralNamesPtr = std::unique_ptr<GENERAL_NAMES, deleter_from_fn<&FreeList>>;
118+
TGeneralNamesPtr subjectAltNames((GENERAL_NAMES*)X509_get_ext_d2i(x509.get(), NID_subject_alt_name, NULL, NULL));
119+
if (!subjectAltNames) {
120+
return result;
121+
}
122+
const int subjectAltNamesCount = sk_GENERAL_NAME_num(subjectAltNames.get());
123+
if (subjectAltNamesCount <= 0) {
124+
return result;
125+
}
126+
127+
result.reserve(static_cast<size_t>(subjectAltNamesCount) + result.size());
128+
// 2. Additionally find subject alternative names with type=DNS
129+
for (int i = 0; i < subjectAltNamesCount; ++i) {
130+
const GENERAL_NAME* name = sk_GENERAL_NAME_value(subjectAltNames.get(), i);
131+
if (!name) {
132+
continue;
133+
}
134+
if (name->type == GEN_DNS) {
135+
const ASN1_STRING* value = name->d.dNSName;
136+
if (!value) {
137+
continue;
138+
}
139+
140+
const char* data = reinterpret_cast<const char*>(ASN1_STRING_get0_data(value));
141+
if (!data) {
142+
continue;
143+
}
144+
int size = ASN1_STRING_length(value);
145+
if (size <= 0) {
146+
continue;
147+
}
148+
result.emplace_back(data, static_cast<size_t>(size));
149+
}
150+
}
151+
return result;
152+
}
153+
103154
TString X509CertificateReader::GetFingerprint(const X509Ptr& x509) {
104155
static constexpr size_t FINGERPRINT_LENGTH = SHA_DIGEST_LENGTH;
105156
unsigned char fingerprint[FINGERPRINT_LENGTH];
@@ -109,14 +160,16 @@ TString X509CertificateReader::GetFingerprint(const X509Ptr& x509) {
109160
return HexEncode(fingerprint, FINGERPRINT_LENGTH);
110161
}
111162

112-
TCertificateAuthorizationParams::TCertificateAuthorizationParams(const TDN& dn, bool requireSameIssuer, const std::vector<TString>& groups)
163+
TCertificateAuthorizationParams::TCertificateAuthorizationParams(const TDN& dn, const std::optional<TRDN>& subjectDns, bool requireSameIssuer, const std::vector<TString>& groups)
113164
: SubjectDn(dn)
165+
, SubjectDns(subjectDns)
114166
, RequireSameIssuer(requireSameIssuer)
115167
, Groups(groups)
116168
{}
117169

118-
TCertificateAuthorizationParams::TCertificateAuthorizationParams(TDN&& dn, bool requireSameIssuer, std::vector<TString>&& groups)
170+
TCertificateAuthorizationParams::TCertificateAuthorizationParams(TDN&& dn, std::optional<TRDN>&& subjectDns, bool requireSameIssuer, std::vector<TString>&& groups)
119171
: SubjectDn(std::move(dn))
172+
, SubjectDns(std::move(subjectDns))
120173
, RequireSameIssuer(requireSameIssuer)
121174
, Groups(std::move(groups))
122175
{}
@@ -127,59 +180,44 @@ TCertificateAuthorizationParams::TDN& TCertificateAuthorizationParams::TDN::AddR
127180
}
128181

129182
TCertificateAuthorizationParams::operator bool() const {
130-
return SubjectDn;
183+
return SubjectDn || SubjectDns;
131184
}
132185

133-
bool TCertificateAuthorizationParams::CheckSubject(const std::unordered_map<TString, std::vector<TString>>& subjectDescription) const {
134-
bool isDescriptionMatched = false;
135-
for (const auto& rdn: SubjectDn.RDNs) {
136-
isDescriptionMatched = false;
186+
bool TCertificateAuthorizationParams::CheckSubject(const std::unordered_map<TString, std::vector<TString>>& subjectDescription, const std::vector<TString>& subjectDns) const {
187+
for (const TRDN& rdn: SubjectDn.RDNs) {
137188
auto fieldIt = subjectDescription.find(rdn.Attribute);
138189
if (fieldIt == subjectDescription.cend()) {
139-
break;
190+
return false;
140191
}
141192

142193
const auto& attributeValues = fieldIt->second;
143-
bool attributeMatched = false;
144-
for (const auto& attributeValue : attributeValues) {
145-
attributeMatched = false;
146-
for (const auto& value: rdn.Values) {
147-
if (value == attributeValue) {
148-
attributeMatched = true;
149-
break;
150-
}
151-
}
152-
if (!attributeMatched) {
153-
for (const auto& suffix: rdn.Suffixes) {
154-
if (attributeValue.EndsWith(suffix)) {
155-
attributeMatched = true;
156-
break;
157-
}
158-
}
159-
}
160-
if (!attributeMatched) {
194+
if (!rdn.Match(attributeValues)) {
195+
return false;
196+
}
197+
}
198+
199+
if (SubjectDns) {
200+
bool dnsMatched = false;
201+
for (const TString& dns : subjectDns) {
202+
if (SubjectDns->Match(dns)) {
203+
dnsMatched = true;
161204
break;
162205
}
163206
}
164-
if (!attributeMatched) {
165-
isDescriptionMatched = false;
166-
break;
207+
if (!dnsMatched) {
208+
return false;
167209
}
168-
isDescriptionMatched = true;
169210
}
170211

171-
if (isDescriptionMatched) {
172-
return true;
173-
}
174-
return false;
212+
return true;
175213
}
176214

177215
TCertificateAuthorizationParams::TDN::operator bool() const {
178216
return !RDNs.empty();
179217
}
180218

181-
TCertificateAuthorizationParams::TRDN::TRDN(const TString& Attribute)
182-
:Attribute(Attribute)
219+
TCertificateAuthorizationParams::TRDN::TRDN(const TString& attribute)
220+
: Attribute(attribute)
183221
{}
184222

185223
TCertificateAuthorizationParams::TRDN& TCertificateAuthorizationParams::TRDN::AddValue(const TString& val)
@@ -194,4 +232,30 @@ TCertificateAuthorizationParams::TRDN& TCertificateAuthorizationParams::TRDN::Ad
194232
return *this;
195233
}
196234

235+
bool TCertificateAuthorizationParams::TRDN::Match(const TString& value) const
236+
{
237+
for (const auto& v : Values) {
238+
if (value == v) {
239+
return true;
240+
}
241+
}
242+
for (const auto& s : Suffixes) {
243+
if (value.EndsWith(s)) {
244+
return true;
245+
}
246+
}
247+
248+
return false;
249+
}
250+
251+
bool TCertificateAuthorizationParams::TRDN::Match(const std::vector<TString>& values) const
252+
{
253+
for (const auto& value : values) {
254+
if (!Match(value)) {
255+
return false;
256+
}
257+
}
258+
return true;
259+
}
260+
197261
} //namespace NKikimr {

0 commit comments

Comments
 (0)