This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new b94da20d8b Fix BZ 69598 - release service account token if it changes
b94da20d8b is described below
commit b94da20d8b8802343cd2d7a36af0b7b1c8affcf7
Author: Mark Thomas <[email protected]>
AuthorDate: Thu Feb 27 08:49:20 2025 +0000
Fix BZ 69598 - release service account token if it changes
---
.../cloud/KubernetesMembershipProvider.java | 41 ++++++++++++++++++++--
.../membership/cloud/LocalStrings.properties | 1 +
.../membership/cloud/TokenStreamProvider.java | 9 ++++-
webapps/docs/changelog.xml | 9 +++++
4 files changed, 57 insertions(+), 3 deletions(-)
diff --git
a/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
b/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
index 4d4d35e5bd..59ff620b23 100644
---
a/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
+++
b/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
@@ -24,6 +24,8 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
@@ -43,8 +45,13 @@ import org.apache.tomcat.util.json.JSONParser;
*/
public class KubernetesMembershipProvider extends CloudMembershipProvider {
+
private static final Log log =
LogFactory.getLog(KubernetesMembershipProvider.class);
+ private Path saTokenPath;
+ private FileTime saTokenLastModifiedTime;
+
+
@Override
public void start(int level) throws Exception {
if ((level & MembershipService.MBR_RX) == 0) {
@@ -80,8 +87,10 @@ public class KubernetesMembershipProvider extends
CloudMembershipProvider {
saTokenFile =
"/var/run/secrets/kubernetes.io/serviceaccount/token";
}
try {
- byte[] bytes =
Files.readAllBytes(FileSystems.getDefault().getPath(saTokenFile));
+ saTokenPath = FileSystems.getDefault().getPath(saTokenFile);
+ byte[] bytes = Files.readAllBytes(saTokenPath);
streamProvider = new TokenStreamProvider(new String(bytes,
StandardCharsets.US_ASCII), caCertFile);
+ saTokenLastModifiedTime =
Files.getLastModifiedTime(saTokenPath);
} catch (IOException e) {
log.error(sm.getString("kubernetesMembershipProvider.streamError"), e);
}
@@ -122,6 +131,7 @@ public class KubernetesMembershipProvider extends
CloudMembershipProvider {
heartbeat();
}
+
@Override
public boolean stop(int level) throws Exception {
try {
@@ -131,12 +141,15 @@ public class KubernetesMembershipProvider extends
CloudMembershipProvider {
}
}
+
@Override
protected Member[] fetchMembers() {
if (streamProvider == null) {
return new Member[0];
}
+ reloadSaTokenIfChanged();
+
List<MemberImpl> members = new ArrayList<>();
try (InputStream stream = streamProvider.openStream(url, headers,
connectionTimeout, readTimeout);
@@ -149,6 +162,31 @@ public class KubernetesMembershipProvider extends
CloudMembershipProvider {
return members.toArray(new Member[0]);
}
+
+ private void reloadSaTokenIfChanged() {
+ if (saTokenPath == null) {
+ // Service account token not being used.
+ return;
+ }
+ if (!Files.exists(saTokenPath)) {
+ // If the service account token is being used, this path should
exist
+
log.warn(sm.getString("kubernetesMembershipProvider.serviceAccountTokenMissing",
saTokenPath));
+ return;
+ }
+ try {
+ FileTime oldSaTokenLastModifiedTime = saTokenLastModifiedTime;
+ saTokenLastModifiedTime = Files.getLastModifiedTime(saTokenPath);
+ // Use != to protect against clock issues
+ if (!saTokenLastModifiedTime.equals(oldSaTokenLastModifiedTime)) {
+ byte[] bytes = Files.readAllBytes(saTokenPath);
+ ((TokenStreamProvider)streamProvider).setToken(new
String(bytes, StandardCharsets.US_ASCII));
+ }
+ } catch (IOException e) {
+
log.error(sm.getString("kubernetesMembershipProvider.streamError"), e);
+ }
+ }
+
+
@SuppressWarnings("unchecked")
protected void parsePods(Reader reader, List<MemberImpl> members) {
JSONParser parser = new JSONParser(reader);
@@ -239,5 +277,4 @@ public class KubernetesMembershipProvider extends
CloudMembershipProvider {
log.error(sm.getString("kubernetesMembershipProvider.jsonError"),
e);
}
}
-
}
diff --git
a/java/org/apache/catalina/tribes/membership/cloud/LocalStrings.properties
b/java/org/apache/catalina/tribes/membership/cloud/LocalStrings.properties
index da3463569f..f7e6e6e872 100644
--- a/java/org/apache/catalina/tribes/membership/cloud/LocalStrings.properties
+++ b/java/org/apache/catalina/tribes/membership/cloud/LocalStrings.properties
@@ -38,6 +38,7 @@ kubernetesMembershipProvider.jsonError=JSON error
kubernetesMembershipProvider.memberError=Error creating member
kubernetesMembershipProvider.noKey=Client certificate key was not specified in
the environment
kubernetesMembershipProvider.noNamespace=Namespace not set
+kubernetesMembershipProvider.serviceAccountTokenMissing=Service account token
not found at [{0}]
kubernetesMembershipProvider.streamError=Failed to open stream
tokenStream.failedConnection=Failed connection to [{0}] with token [{1}]
diff --git
a/java/org/apache/catalina/tribes/membership/cloud/TokenStreamProvider.java
b/java/org/apache/catalina/tribes/membership/cloud/TokenStreamProvider.java
index 0c66e5e4d9..c1efc7a6e6 100644
--- a/java/org/apache/catalina/tribes/membership/cloud/TokenStreamProvider.java
+++ b/java/org/apache/catalina/tribes/membership/cloud/TokenStreamProvider.java
@@ -29,6 +29,7 @@ public class TokenStreamProvider extends
AbstractStreamProvider {
private String token;
private SSLSocketFactory factory;
+
TokenStreamProvider(String token, String caCertFile) throws Exception {
this.token = token;
TrustManager[] trustManagers = configureCaCert(caCertFile);
@@ -37,11 +38,18 @@ public class TokenStreamProvider extends
AbstractStreamProvider {
this.factory = context.getSocketFactory();
}
+
@Override
protected SSLSocketFactory getSocketFactory() {
return factory;
}
+
+ protected void setToken(String token) {
+ this.token = token;
+ }
+
+
@Override
public InputStream openStream(String url, Map<String,String> headers, int
connectTimeout, int readTimeout)
throws IOException {
@@ -56,5 +64,4 @@ public class TokenStreamProvider extends
AbstractStreamProvider {
throw new IOException(sm.getString("tokenStream.failedConnection",
url, token), e);
}
}
-
}
\ No newline at end of file
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 4b0d2d665b..71dda74844 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -161,6 +161,15 @@
</fix>
</changelog>
</subsection>
+ <subsection name="Cluster">
+ <changelog>
+ <add>
+ <bug>69598</bug>: Add detection of service account token changes to the
+ <code>KubernetesMembershipProvider</code> implementation and reload the
+ token if it changes. Based on a patch by Miroslav Jezbera. (markt)
+ </add>
+ </changelog>
+ </subsection>
<subsection name="Other">
<changelog>
<add>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]