aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/go/internal/vespa/target_cloud.go10
-rw-r--r--container-disc/abi-spec.json1
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java5
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java96
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java2
-rw-r--r--searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp5
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.cpp6
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.h3
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/match_phase_limit_calculator.h16
-rw-r--r--searchcore/src/vespa/searchcore/proton/matching/match_phase_limiter.cpp8
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java9
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java9
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java53
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java8
15 files changed, 190 insertions, 45 deletions
diff --git a/client/go/internal/vespa/target_cloud.go b/client/go/internal/vespa/target_cloud.go
index 31108dae51f..708810061d2 100644
--- a/client/go/internal/vespa/target_cloud.go
+++ b/client/go/internal/vespa/target_cloud.go
@@ -42,9 +42,10 @@ type cloudTarget struct {
}
type deploymentEndpoint struct {
- Cluster string `json:"cluster"`
- URL string `json:"url"`
- Scope string `json:"scope"`
+ Cluster string `json:"cluster"`
+ URL string `json:"url"`
+ Scope string `json:"scope"`
+ AuthMethod string `json:"authMethod"`
}
type deploymentResponse struct {
@@ -370,6 +371,9 @@ func (t *cloudTarget) discoverEndpoints(timeout time.Duration) (map[string]strin
if endpoint.Scope != "zone" {
continue
}
+ if endpoint.AuthMethod == "token" {
+ continue
+ }
urlsByCluster[endpoint.Cluster] = endpoint.URL
}
return true, nil
diff --git a/container-disc/abi-spec.json b/container-disc/abi-spec.json
index 92f21af0cde..49d740d369d 100644
--- a/container-disc/abi-spec.json
+++ b/container-disc/abi-spec.json
@@ -16,6 +16,7 @@
"public abstract java.lang.String getRoleToken(java.lang.String, java.lang.String)",
"public abstract java.lang.String getAccessToken(java.lang.String)",
"public abstract java.lang.String getAccessToken(java.lang.String, java.util.List)",
+ "public abstract java.lang.String getAccessToken(java.lang.String, java.util.List, java.util.List)",
"public abstract java.util.List getIdentityCertificate()",
"public abstract java.security.cert.X509Certificate getRoleCertificate(java.lang.String, java.lang.String)",
"public abstract java.security.PrivateKey getPrivateKey()",
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java b/container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java
index e644ab1664e..f91d25534cf 100644
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java
+++ b/container-disc/src/main/java/com/yahoo/container/jdisc/AthenzIdentityProviderProvider.java
@@ -71,6 +71,11 @@ public class AthenzIdentityProviderProvider implements Provider<AthenzIdentityPr
}
@Override
+ public String getAccessToken(String domain, List<String> roles, List<String> proxyPrincipal) {
+ throw new UnsupportedOperationException(message);
+ }
+
+ @Override
public List<X509Certificate> getIdentityCertificate() {
throw new UnsupportedOperationException(message);
}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java
index ef328fca760..fc55512f7f7 100644
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java
+++ b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java
@@ -8,21 +8,117 @@ import java.security.cert.X509Certificate;
import java.util.List;
/**
+ * Provides convenience methods to interact with Athenz authenticated services
+ *
* @author mortent
+ * @author bjorncs
*/
public interface AthenzIdentityProvider {
+ /**
+ * Get the Athenz domain associated with this identity provider.
+ *
+ * @return The Athenz domain.
+ */
String domain();
+
+ /**
+ * Get the Athenz service name associated with this identity provider.
+ *
+ * @return The Athenz service name.
+ */
String service();
+
+ /**
+ * Get the SSLContext used for authenticating with the configured Athenz service
+ *
+ * @return An SSLContext for identity authentication.
+ */
SSLContext getIdentitySslContext();
+
+ /**
+ * Get the SSLContext for authenticating with an Athenz role
+ *
+ * @param domain Athenz domain name for the role
+ * @param role Athenz role name
+ * @return A SSLContext for role authentication within the specified domain and role.
+ */
SSLContext getRoleSslContext(String domain, String role);
+
+ /**
+ * Get a role token for the specified Athenz domain.
+ *
+ * @param domain The Athenz domain for the role token
+ * @return A role token for the specified domain.
+ */
String getRoleToken(String domain);
+
+ /**
+ * Get a role token for a specific Athenz role.
+ *
+ * @param domain The Athenz domain name for the role
+ * @param role The Athenz role name
+ * @return A role token for the specified domain and role.
+ */
String getRoleToken(String domain, String role);
+
+ /**
+ * Get an access token for the specified Athenz domain.
+ *
+ * @param domain Athenz domain name for the token
+ * @return An access token for the specified domain.
+ */
String getAccessToken(String domain);
+
+ /**
+ * Get an access token for a list of roles in an Athenz domain.
+ *
+ * @param domain Athenz domain name for the roles
+ * @param roles The list of Athenz roles names
+ * @return An access token for the specified roles.
+ */
String getAccessToken(String domain, List<String> roles);
+
+ /**
+ * Get an access token for the specified Athenz domain.
+ *
+ * @param domain Athenz domain name
+ * @param roles List of Athenz role names. Empty list or null will fetch a token for all roles in the domain.
+ * @param proxyPrincipal List of principals to allow proxying the token. Each principal must be provided as: <em>&lt;domain&gt;:service.&lt;service&gt;</em>
+ * Empty list or <em>null</em> will return a token without proxy principals.
+ * @return An access token for the specified domain.
+ */
+ String getAccessToken(String domain, List<String> roles, List<String> proxyPrincipal);
+
+ /**
+ * Get the X.509 identity certificate associated with this identity provider.
+ *
+ * @return The X.509 identity certificate.
+ */
List<X509Certificate> getIdentityCertificate();
+
+ /**
+ * Get the X.509 role certificate for a specific Athenz role.
+ *
+ * @param domain Athenz domain name for the role
+ * @param role Athenz role name
+ * @return An X.509 role certificate for the specified domain and role.
+ */
X509Certificate getRoleCertificate(String domain, String role);
+
+ /**
+ * Get the private key associated with this identity provider.
+ *
+ * @return The private key used for authentication.
+ */
PrivateKey getPrivateKey();
+
+ /**
+ * Get the path to the trust store used for SSL verification.
+ *
+ * @return The path to the trust store.
+ */
Path trustStorePath();
+
void deconstruct();
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
index 9a4e47ed154..192d90e1da1 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java
@@ -783,9 +783,9 @@ public class Nodes {
if (host.allocation().map(alloc -> alloc.membership().retired()).orElse(false)) return false;
if (dynamicProvisioning)
- return EnumSet.of(Node.State.active, Node.State.ready, Node.State.provisioned).contains(host.state());
+ return EnumSet.of(State.provisioned, State.ready, State.reserved, State.active).contains(host.state());
else
- return host.state() == Node.State.active;
+ return host.state() == State.active;
}
public boolean suspended(Node node) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
index b92d6fb6d18..7e7c78f82f4 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodePrioritizer.java
@@ -211,7 +211,7 @@ public class NodePrioritizer {
/**
* We may regret that a non-active node is allocated to a host and not offer it to the application
- * now, e.g if we want to retire the host.
+ * now, e.g., if we want to retire the host.
*
* @return true if we still want to allocate the given node to its parent
*/
diff --git a/searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp b/searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp
index 9f4edac9ba4..21c572995d3 100644
--- a/searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp
+++ b/searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp
@@ -181,6 +181,7 @@ TEST("require that max group size is calculated correctly") {
TEST("require that the attribute limiter works correctly") {
FakeRequestContext requestContext;
MockRangeLocator rangeLocator;
+ constexpr double HIT_RATE = 0.1;
for (int i = 0; i <= 7; ++i) {
bool descending = (i & 1) != 0;
bool strict = (i & 2) != 0;
@@ -190,10 +191,10 @@ TEST("require that the attribute limiter works correctly") {
"category", 10.0, AttributeLimiter::LOOSE);
EXPECT_EQUAL(0u, searchable.create_cnt);
EXPECT_FALSE(limiter.was_used());
- SearchIterator::UP s1 = limiter.create_search(42, diverse ? 3 : 42, strict);
+ SearchIterator::UP s1 = limiter.create_search(42, diverse ? 3 : 42, HIT_RATE, strict);
EXPECT_TRUE(limiter.was_used());
EXPECT_EQUAL(1u, searchable.create_cnt);
- SearchIterator::UP s2 = limiter.create_search(42, diverse ? 3 : 42, strict);
+ SearchIterator::UP s2 = limiter.create_search(42, diverse ? 3 : 42, HIT_RATE, strict);
EXPECT_EQUAL(1u, searchable.create_cnt);
auto *ms = dynamic_cast<MockSearch*>(s1.get());
ASSERT_TRUE(ms != nullptr);
diff --git a/searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.cpp b/searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.cpp
index 9911b04e087..4dec253946f 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.cpp
@@ -76,8 +76,8 @@ toString(AttributeLimiter::DiversityCutoffStrategy strategy)
return (strategy == AttributeLimiter::DiversityCutoffStrategy::STRICT) ? STRICT_STR : LOOSE_STR;
}
-SearchIterator::UP
-AttributeLimiter::create_search(size_t want_hits, size_t max_group_size, bool strictSearch)
+std::unique_ptr<SearchIterator>
+AttributeLimiter::create_search(size_t want_hits, size_t max_group_size, double hit_rate, bool strictSearch)
{
std::lock_guard<std::mutex> guard(_lock);
const uint32_t my_field_id = 0;
@@ -99,7 +99,7 @@ AttributeLimiter::create_search(size_t want_hits, size_t max_group_size, bool st
FieldSpecList field; // single field API is protected
field.add(FieldSpec(_attribute_name, my_field_id, my_handle));
_blueprint = _searchable_attributes.createBlueprint(_requestContext, field, node);
- _blueprint->fetchPostings(ExecuteInfo::create(strictSearch, &_requestContext.getDoom()));
+ _blueprint->fetchPostings(ExecuteInfo::create(strictSearch, strictSearch ? 1.0F : hit_rate, &_requestContext.getDoom()));
_estimatedHits.store(_blueprint->getState().estimate().estHits, std::memory_order_relaxed);
_blueprint->freeze();
}
diff --git a/searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.h b/searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.h
index 676dbf26108..df0acccbd7a 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.h
+++ b/searchcore/src/vespa/searchcore/proton/matching/attribute_limiter.h
@@ -31,6 +31,7 @@ class RangeQueryLocator;
class AttributeLimiter
{
public:
+ using SearchIterator = search::queryeval::SearchIterator;
enum DiversityCutoffStrategy { LOOSE, STRICT};
AttributeLimiter(const RangeQueryLocator & _rangeQueryLocator,
search::queryeval::Searchable &searchable_attributes,
@@ -40,7 +41,7 @@ public:
double diversityCutoffFactor,
DiversityCutoffStrategy diversityCutoffStrategy);
~AttributeLimiter();
- std::unique_ptr<search::queryeval::SearchIterator> create_search(size_t want_hits, size_t max_group_size, bool strictSearch);
+ std::unique_ptr<SearchIterator> create_search(size_t want_hits, size_t max_group_size, double hit_rate, bool strictSearch);
bool was_used() const;
ssize_t getEstimatedHits() const;
static DiversityCutoffStrategy toDiversityCutoffStrategy(vespalib::stringref strategy);
diff --git a/searchcore/src/vespa/searchcore/proton/matching/match_phase_limit_calculator.h b/searchcore/src/vespa/searchcore/proton/matching/match_phase_limit_calculator.h
index 6cbeeebbfa0..c422529ea30 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/match_phase_limit_calculator.h
+++ b/searchcore/src/vespa/searchcore/proton/matching/match_phase_limit_calculator.h
@@ -25,21 +25,21 @@ public:
* @param min_groups the minimum number of diversity groups you want
* @param sample fraction of max_hits to be used as sample size before performing match phase limiting
*/
- MatchPhaseLimitCalculator(size_t max_hits, size_t min_groups, double sample) :
- _max_hits(max_hits),
- _min_groups(std::max(size_t(1), min_groups)),
- _sample_hits(max_hits * sample)
+ MatchPhaseLimitCalculator(size_t max_hits, size_t min_groups, double sample) noexcept
+ : _max_hits(max_hits),
+ _min_groups(std::max(size_t(1), min_groups)),
+ _sample_hits(max_hits * sample)
{}
- size_t sample_hits_per_thread(size_t num_threads) const {
+ size_t sample_hits_per_thread(size_t num_threads) const noexcept {
return std::max(size_t(1), std::max(128 / num_threads, _sample_hits / num_threads));
}
- size_t wanted_num_docs(double hit_rate) const {
+ size_t wanted_num_docs(double hit_rate) const noexcept {
return std::min((double)0x7fffFFFF, std::max(128.0, _max_hits / hit_rate));
}
- size_t estimated_hits(double hit_rate, size_t num_docs) const {
+ size_t estimated_hits(double hit_rate, size_t num_docs) const noexcept {
return (size_t) (hit_rate * num_docs);
}
- size_t max_group_size(size_t wanted_num_docs_in) const {
+ size_t max_group_size(size_t wanted_num_docs_in) const noexcept {
return (wanted_num_docs_in / _min_groups);
}
};
diff --git a/searchcore/src/vespa/searchcore/proton/matching/match_phase_limiter.cpp b/searchcore/src/vespa/searchcore/proton/matching/match_phase_limiter.cpp
index 3d319b84828..908843ca3ca 100644
--- a/searchcore/src/vespa/searchcore/proton/matching/match_phase_limiter.cpp
+++ b/searchcore/src/vespa/searchcore/proton/matching/match_phase_limiter.cpp
@@ -87,11 +87,11 @@ namespace {
template <bool PRE_FILTER>
SearchIterator::UP
-do_limit(AttributeLimiter &limiter_factory, SearchIterator::UP search,
+do_limit(AttributeLimiter &limiter_factory, SearchIterator::UP search, double match_freq,
size_t wanted_num_docs, size_t max_group_size,
uint32_t current_id, uint32_t end_id)
{
- SearchIterator::UP limiter = limiter_factory.create_search(wanted_num_docs, max_group_size, PRE_FILTER);
+ SearchIterator::UP limiter = limiter_factory.create_search(wanted_num_docs, max_group_size, match_freq, PRE_FILTER);
limiter = search->andWith(std::move(limiter), wanted_num_docs);
if (limiter) {
search = std::make_unique<LimitedSearchT<PRE_FILTER>>(std::move(limiter), std::move(search));
@@ -139,8 +139,8 @@ MatchPhaseLimiter::maybe_limit(SearchIterator::UP search, double match_freq, siz
use_pre_filter ? "pre" : "post", match_freq, num_docs, max_filter_docs, wanted_num_docs,
max_group_size, current_id, end_id, total_query_hits);
return (use_pre_filter)
- ? do_limit<true>(_limiter_factory, std::move(search), wanted_num_docs, max_group_size, current_id, end_id)
- : do_limit<false>(_limiter_factory, std::move(search), wanted_num_docs, max_group_size, current_id, end_id);
+ ? do_limit<true>(_limiter_factory, std::move(search), match_freq, wanted_num_docs, max_group_size, current_id, end_id)
+ : do_limit<false>(_limiter_factory, std::move(search), match_freq, wanted_num_docs, max_group_size, current_id, end_id);
}
void
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
index 1a921c3b3ad..101d40be491 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
@@ -141,16 +141,21 @@ public class DefaultZtsClient extends ClientBase implements ZtsClient {
}
@Override
- public AthenzAccessToken getAccessToken(AthenzDomain domain, List<AthenzIdentity> proxyPrincipals) {
+ public AthenzAccessToken getAccessToken(AthenzDomain domain, List<AthenzIdentity> proxyPrincipals) {
return this.getAccessTokenImpl(List.of(new AthenzResourceName(domain, "domain")), proxyPrincipals);
}
@Override
public AthenzAccessToken getAccessToken(List<AthenzRole> athenzRole) {
+ return getAccessToken(athenzRole, List.of());
+ }
+
+ @Override
+ public AthenzAccessToken getAccessToken(List<AthenzRole> athenzRole, List<AthenzIdentity> proxyPrincipals) {
List<AthenzResourceName> athenzResourceNames = athenzRole.stream()
.map(AthenzRole::toResourceName)
.toList();
- return this.getAccessTokenImpl(athenzResourceNames, List.of());
+ return this.getAccessTokenImpl(athenzResourceNames, proxyPrincipals);
}
private AthenzAccessToken getAccessTokenImpl(List<AthenzResourceName> resources, List<AthenzIdentity> proxyPrincipals) {
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
index 67a53715cec..0528042da16 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
@@ -129,6 +129,15 @@ public interface ZtsClient extends AutoCloseable {
AthenzAccessToken getAccessToken(List<AthenzRole> athenzRole);
/**
+ * Fetch an access token for the target roles
+ *
+ * @param athenzRole List of athenz roles to get access token for
+ * @param proxyPrincipals List of principals to allow proxying token
+ * @return An Athenz access token
+ */
+ AthenzAccessToken getAccessToken(List<AthenzRole> athenzRole, List<AthenzIdentity> proxyPrincipals);
+
+ /**
* Fetch role certificate for the target domain and role
*
* @param role Target role
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
index 623a8c856bc..a3916cbe080 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
@@ -20,6 +20,7 @@ import com.yahoo.security.SslContextBuilder;
import com.yahoo.security.X509CertificateWithKey;
import com.yahoo.vespa.athenz.api.AthenzAccessToken;
import com.yahoo.vespa.athenz.api.AthenzDomain;
+import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.api.ZToken;
@@ -28,6 +29,7 @@ import com.yahoo.vespa.athenz.client.zts.ZtsClient;
import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
import com.yahoo.vespa.athenz.tls.AthenzX509CertificateUtils;
+import com.yahoo.vespa.athenz.utils.AthenzIdentities;
import com.yahoo.vespa.athenz.utils.SiaUtils;
import javax.net.ssl.SSLContext;
@@ -43,6 +45,7 @@ import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -89,8 +92,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
private final Map<AthenzRole, MutableX509KeyManager> roleKeyManagerCache;
private final LoadingCache<AthenzRole, ZToken> roleSpecificRoleTokenCache;
private final LoadingCache<AthenzDomain, ZToken> domainSpecificRoleTokenCache;
- private final LoadingCache<AthenzDomain, AthenzAccessToken> domainSpecificAccessTokenCache;
- private final LoadingCache<List<AthenzRole>, AthenzAccessToken> roleSpecificAccessTokenCache;
+ private final LoadingCache<AccessTokenCacheKey, AthenzAccessToken> accessTokenCache;
private final CsrGenerator csrGenerator;
@Inject
@@ -115,8 +117,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
this.roleKeyManagerCache = new HashMap<>();
this.roleSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
this.domainSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
- this.domainSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
- this.roleSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
+ this.accessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
this.csrGenerator = new CsrGenerator(config.athenzDnsSuffix(), config.configserverIdentityName());
this.autoReloadingX509KeyManager = autoReloadingX509KeyManager;
this.identitySslContext = createIdentitySslContext(autoReloadingX509KeyManager, trustStore);
@@ -221,7 +222,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
@Override
public String getAccessToken(String domain) {
try {
- return domainSpecificAccessTokenCache.get(new AthenzDomain(domain)).value();
+ return accessTokenCache.get(AccessTokenCacheKey.from(domain, List.of(), List.of())).value();
} catch (Exception e) {
throw new AthenzIdentityProviderException("Could not retrieve access token: " + e.getMessage(), e);
}
@@ -230,10 +231,16 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
@Override
public String getAccessToken(String domain, List<String> roles) {
try {
- List<AthenzRole> roleList = roles.stream()
- .map(roleName -> new AthenzRole(domain, roleName))
- .toList();
- return roleSpecificAccessTokenCache.get(roleList).value();
+ return accessTokenCache.get(AccessTokenCacheKey.from(domain, roles, List.of())).value();
+ } catch (Exception e) {
+ throw new AthenzIdentityProviderException("Could not retrieve access token: " + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public String getAccessToken(String domain, List<String> roles, List<String> proxyPrincipals) {
+ try {
+ return accessTokenCache.get(AccessTokenCacheKey.from(domain, roles, proxyPrincipals)).value();
} catch (Exception e) {
throw new AthenzIdentityProviderException("Could not retrieve access token: " + e.getMessage(), e);
}
@@ -305,15 +312,15 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
}
}
- private AthenzAccessToken createAccessToken(AthenzDomain domain) {
+ private AthenzAccessToken createAccessToken(AccessTokenCacheKey cacheKey) {
+ List<AthenzRole> roles = Optional.ofNullable(cacheKey.roles()).orElse(List.of());
+ List<AthenzIdentity> proxyPrincipals = Optional.ofNullable(cacheKey.proxyPrincipals()).orElse(List.of());
try (ZtsClient client = createZtsClient()) {
- return client.getAccessToken(domain);
- }
- }
-
- private AthenzAccessToken createAccessToken(List<AthenzRole> roles) {
- try (ZtsClient client = createZtsClient()) {
- return client.getAccessToken(roles);
+ if (roles.isEmpty()) {
+ return client.getAccessToken(cacheKey.domain(), proxyPrincipals);
+ } else {
+ return client.getAccessToken(roles, proxyPrincipals);
+ }
}
}
@@ -349,5 +356,15 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
log.log(Level.WARNING, "Failed to update metrics: " + t.getMessage(), t);
}
}
+ private record AccessTokenCacheKey(AthenzDomain domain, List<AthenzRole> roles, List<AthenzIdentity> proxyPrincipals) {
+ static AccessTokenCacheKey from(String domain, List<String> roles, List<String> proxyPrincipals) {
+ List<AthenzRole> roleList = Optional.ofNullable(roles).orElse(List.of()).stream()
+ .map(roleName -> new AthenzRole(domain, roleName))
+ .toList();
+ List<AthenzIdentity> proxyPrincipalList = Optional.ofNullable(proxyPrincipals).orElse(List.of()).stream()
+ .map(AthenzIdentities::from)
+ .toList();
+ return new AccessTokenCacheKey(new AthenzDomain(domain), roleList, proxyPrincipalList);
+ }
+ }
}
-
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java
index 4058af31dde..a881dc2b100 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java
@@ -261,6 +261,11 @@ public final class LegacyAthenzIdentityProviderImpl extends AbstractComponent im
}
@Override
+ public String getAccessToken(String domain, List<String> roles, List<String> proxyPrincipal) {
+ throw new UnsupportedOperationException("Not implemented in legacy client");
+ }
+
+ @Override
public PrivateKey getPrivateKey() {
return credentials.getKeyPair().getPrivate();
}
@@ -383,7 +388,8 @@ public final class LegacyAthenzIdentityProviderImpl extends AbstractComponent im
try {
Instant expirationTime = getExpirationTime(credentials);
Duration remainingLifetime = Duration.between(clock.instant(), expirationTime);
- metric.set(CERTIFICATE_EXPIRY_METRIC_NAME, remainingLifetime.getSeconds(), null);
+ Metric.Context dimensions = metric.createContext(Map.of("implementation", this.getClassName()));
+ metric.set(CERTIFICATE_EXPIRY_METRIC_NAME, remainingLifetime.getSeconds(), dimensions);
} catch (Throwable t) {
log.log(Level.WARNING, "Failed to update metrics: " + t.getMessage(), t);
}