diff --git a/libs/java/auth_core/src/main/java/com/yahoo/athenz/auth/PrivateKeyStore.java b/libs/java/auth_core/src/main/java/com/yahoo/athenz/auth/PrivateKeyStore.java index bb2d8d201b1..8dddd90a8cf 100644 --- a/libs/java/auth_core/src/main/java/com/yahoo/athenz/auth/PrivateKeyStore.java +++ b/libs/java/auth_core/src/main/java/com/yahoo/athenz/auth/PrivateKeyStore.java @@ -68,6 +68,7 @@ default String getApplicationSecret(String appName, String keyName) { /** * Retrieve the application secret based on the configured key name as char[]. + * @deprecated * The application name specifies what component is this secret for; * for example, jdbc for accessing the secret for the jdbc user. * The default implementation assumes the key name is the secret. @@ -75,8 +76,23 @@ default String getApplicationSecret(String appName, String keyName) { * @param keyName configured value for the secret * @return secret for the given key and application as char[] */ + @Deprecated default char[] getSecret(String appName, String keyName) { final String secret = getApplicationSecret(appName, keyName); return secret != null ? secret.toCharArray() : null; } + + /** + * Retrieve the application secret based on the configured key name as char[]. + * The application name specifies what component is this secret for; + * for example, jdbc for accessing the secret for the jdbc user. + * The default implementation assumes the key name is the secret. + * @param appName application name for the secret + * @param keygroupName key group name for the secret + * @param keyName name of the secret + * @return secret for the given key and application as char[] + */ + default char[] getSecret(String appName, String keygroupName, String keyName) { + return keyName.toCharArray(); + } } diff --git a/libs/java/auth_core/src/main/java/com/yahoo/athenz/auth/impl/AWSParameterStorePrivateKeyStore.java b/libs/java/auth_core/src/main/java/com/yahoo/athenz/auth/impl/AWSParameterStorePrivateKeyStore.java index b04ebdbd2c7..6d0a7a8786c 100644 --- a/libs/java/auth_core/src/main/java/com/yahoo/athenz/auth/impl/AWSParameterStorePrivateKeyStore.java +++ b/libs/java/auth_core/src/main/java/com/yahoo/athenz/auth/impl/AWSParameterStorePrivateKeyStore.java @@ -50,7 +50,7 @@ public class AWSParameterStorePrivateKeyStore implements PrivateKeyStore { } @Override - public char[] getSecret(String appName, String keyName) { + public char[] getSecret(String appName, String keygroupName, String keyName) { return getSsmParameter(keyName).toCharArray(); } diff --git a/libs/java/auth_core/src/test/java/com/yahoo/athenz/auth/impl/AWSParameterStorePrivateKeyStoreTest.java b/libs/java/auth_core/src/test/java/com/yahoo/athenz/auth/impl/AWSParameterStorePrivateKeyStoreTest.java index 16a451b6066..089a565e8e2 100644 --- a/libs/java/auth_core/src/test/java/com/yahoo/athenz/auth/impl/AWSParameterStorePrivateKeyStoreTest.java +++ b/libs/java/auth_core/src/test/java/com/yahoo/athenz/auth/impl/AWSParameterStorePrivateKeyStoreTest.java @@ -49,7 +49,7 @@ public void testGetSecret() { when(ssmClient.getParameter(any(Consumer.class))) .thenReturn(GetParameterResponse.builder().parameter(Parameter.builder().value("secret").build()).build()); AWSParameterStorePrivateKeyStore store = (AWSParameterStorePrivateKeyStore)getFactory(ssmClient).create(); - assertEquals(store.getSecret("app1", "key1"), "secret".toCharArray()); + assertEquals(store.getSecret("app1", null, "key1"), "secret".toCharArray()); } @Test diff --git a/libs/java/server_k8s_common/README.md b/libs/java/server_k8s_common/README.md new file mode 100644 index 00000000000..4db0efd2330 --- /dev/null +++ b/libs/java/server_k8s_common/README.md @@ -0,0 +1,12 @@ +Athenz Server Common Classes +============================ + +Common classes used throughout Athenz Server components if server is deployed in Kubernetes. + +- KeyStore: PrivateKeyStore implementation using Kubernetes secrets + +## License + +Copyright The Athenz Authors + +Licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) diff --git a/libs/java/server_k8s_common/pom.xml b/libs/java/server_k8s_common/pom.xml new file mode 100644 index 00000000000..d990792ec03 --- /dev/null +++ b/libs/java/server_k8s_common/pom.xml @@ -0,0 +1,63 @@ + + + + 4.0.0 + + + com.yahoo.athenz + athenz + 1.11.60-SNAPSHOT + ../../../pom.xml + + + athenz-server-k8s-common + athenz-k8s-server-common + Athenz Kubernetes Server Common Packages + jar + + + 1.00 + + + + + org.slf4j + slf4j-api + ${slf4j.server.version} + + + ch.qos.logback + logback-classic + ${logback.server.version} + test + + + com.squareup.okhttp3 + mockwebserver + ${okhttp3.mockwebserver.version} + test + + + com.yahoo.athenz + athenz-auth-core + ${project.parent.version} + + + io.kubernetes + client-java + ${kubernetes-client.version} + + + + diff --git a/libs/java/server_k8s_common/src/main/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStore.java b/libs/java/server_k8s_common/src/main/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStore.java new file mode 100644 index 00000000000..a6d317ba8d2 --- /dev/null +++ b/libs/java/server_k8s_common/src/main/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStore.java @@ -0,0 +1,112 @@ +/* + * Copyright The Athenz Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.athenz.server.k8s.common.impl; + +import com.yahoo.athenz.auth.PrivateKeyStore; +import com.yahoo.athenz.auth.ServerPrivateKey; +import com.yahoo.athenz.auth.util.Crypto; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.openapi.apis.CoreV1Api; +import io.kubernetes.client.openapi.models.V1Secret; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; + +public class KubernetesSecretPrivateKeyStore implements PrivateKeyStore { + + private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private static final String ZMS_SERVICE = "zms"; + private static final String ZTS_SERVICE = "zts"; + private static final String MSD_SERVICE = "msd"; + + private static final String ATHENZ_PROP_K8S_ZMS_KEY_NAME = "athenz.k8s.zms.key_name"; + private static final String ATHENZ_PROP_K8S_ZMS_KEY_ID_NAME = "athenz.k8s.zms.key_id_name"; + private static final String ATHENZ_PROP_K8S_ZTS_KEY_NAME = "athenz.k8s.zts.key_name"; + private static final String ATHENZ_PROP_K8S_ZTS_KEY_ID_NAME = "athenz.k8s.zts.key_id_name"; + private static final String ATHENZ_PROP_K8S_MSD_KEY_NAME = "athenz.k8s.msd.key_name"; + private static final String ATHENZ_PROP_K8S_MSD_KEY_ID_NAME = "athenz.k8s.msd.key_id_name"; + + private static final String ATHENZ_K8S_DEFAULT_KEY_NAME = "service_k8s_private_key"; + private static final String ATHENZ_K8S_DEFAULT_KEY_ID_NAME = "service_k8s_private_key_id"; + + private final ApiClient k8sClient; + + private static final String ATHENZ_K8S_CONNECT_TIMEOUT = "athenz.k8s.connect_timeout"; + private static final String ATHENZ_K8S_READ_TIMEOUT = "athenz.k8s.read_timeout"; + + public KubernetesSecretPrivateKeyStore(ApiClient k8sClient) { + this.k8sClient = k8sClient; + this.k8sClient.setConnectTimeout(Integer.parseInt(System.getProperty(ATHENZ_K8S_CONNECT_TIMEOUT, "500"))); + this.k8sClient.setReadTimeout(Integer.parseInt(System.getProperty(ATHENZ_K8S_READ_TIMEOUT, "2000"))); + Configuration.setDefaultApiClient(k8sClient); + } + + @Override + public ServerPrivateKey getPrivateKey(String service, String namespace, + String secretName, String algorithm) { + String keyName; + String keyIdName; + final String objectSuffix = "." + algorithm.toLowerCase(); + if (ZMS_SERVICE.equals(service)) { + keyName = System.getProperty(ATHENZ_PROP_K8S_ZMS_KEY_NAME, ATHENZ_K8S_DEFAULT_KEY_NAME) + objectSuffix; + keyIdName = System.getProperty(ATHENZ_PROP_K8S_ZMS_KEY_ID_NAME, ATHENZ_K8S_DEFAULT_KEY_ID_NAME) + objectSuffix; + } else if (ZTS_SERVICE.equals(service)) { + keyName = System.getProperty(ATHENZ_PROP_K8S_ZTS_KEY_NAME, ATHENZ_K8S_DEFAULT_KEY_NAME) + objectSuffix; + keyIdName = System.getProperty(ATHENZ_PROP_K8S_ZTS_KEY_ID_NAME, ATHENZ_K8S_DEFAULT_KEY_ID_NAME) + objectSuffix; + } else if (MSD_SERVICE.equals(service)) { + keyName = System.getProperty(ATHENZ_PROP_K8S_MSD_KEY_NAME, ATHENZ_K8S_DEFAULT_KEY_NAME) + objectSuffix; + keyIdName = System.getProperty(ATHENZ_PROP_K8S_MSD_KEY_ID_NAME, ATHENZ_K8S_DEFAULT_KEY_ID_NAME) + objectSuffix; + } else { + LOG.error("Unknown service specified: {}", service); + return null; + } + + PrivateKey pkey = null; + try { + pkey = Crypto.loadPrivateKey(getSecretFromK8S(namespace, secretName, keyName)); + } catch (Exception ex) { + LOG.error("unable to load private key", ex); + } + return pkey == null ? null : new ServerPrivateKey(pkey, getSecretFromK8S(namespace, secretName, keyIdName)); + } + + @Override + public char[] getSecret(String namespace, String secretName, String keyName) { + return getSecretFromK8S(namespace, secretName, keyName).toCharArray(); + } + + String getSecretFromK8S(String namespace, String secretName, String keyName) { + try { + CoreV1Api api = new CoreV1Api(k8sClient); + V1Secret secret = api.readNamespacedSecret(secretName, namespace).execute(); + if (secret != null && secret.getData() != null && secret.getData().get(keyName) != null) { + return new String(secret.getData().get(keyName), StandardCharsets.UTF_8); + } else { + LOG.error("Unable to retrieve secret={} for key={} from namespace={}", secretName, keyName, namespace); + return ""; + } + } catch (ApiException e) { + LOG.error("Error in retrieving secret={} for key={} from namespace={}", secretName, keyName, namespace); + throw new RuntimeException(e); + } + } +} diff --git a/libs/java/server_k8s_common/src/main/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreFactory.java b/libs/java/server_k8s_common/src/main/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreFactory.java new file mode 100644 index 00000000000..cb8b0781058 --- /dev/null +++ b/libs/java/server_k8s_common/src/main/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright The Athenz Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.athenz.server.k8s.common.impl; + +import com.yahoo.athenz.auth.PrivateKeyStore; +import com.yahoo.athenz.auth.PrivateKeyStoreFactory; +import io.kubernetes.client.util.Config; + +public class KubernetesSecretPrivateKeyStoreFactory implements PrivateKeyStoreFactory { + @Override + public PrivateKeyStore create() { + try { + return new KubernetesSecretPrivateKeyStore(Config.defaultClient()); + } catch (Exception ex) { + throw new RuntimeException("Unable to create KubernetesSecretPrivateKeyStore", ex); + } + } +} diff --git a/libs/java/server_k8s_common/src/test/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreFactoryTest.java b/libs/java/server_k8s_common/src/test/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreFactoryTest.java new file mode 100644 index 00000000000..5ee9702fe97 --- /dev/null +++ b/libs/java/server_k8s_common/src/test/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreFactoryTest.java @@ -0,0 +1,46 @@ +/* + * Copyright The Athenz Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.athenz.server.k8s.common.impl; + +import com.yahoo.athenz.auth.PrivateKeyStore; +import io.kubernetes.client.util.Config; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +public class KubernetesSecretPrivateKeyStoreFactoryTest { + @Test + public void createKubernetesSecretPrivateKeyStore() { + PrivateKeyStore privateKeyStore = new KubernetesSecretPrivateKeyStoreFactory().create(); + assertTrue(privateKeyStore instanceof KubernetesSecretPrivateKeyStore); + } + + @Test + public void createKubernetesSecretPrivateKeyStoreException() { + try (MockedStatic configMockedStatic = Mockito.mockStatic(Config.class)) { + configMockedStatic.when(Config::defaultClient).thenThrow(new RuntimeException("mocked exception")); + try { + new KubernetesSecretPrivateKeyStoreFactory().create(); + fail(); + } catch (RuntimeException ex) { + assertTrue(ex.getMessage().contains("Unable to create KubernetesSecretPrivateKeyStore")); + } + } + } +} diff --git a/libs/java/server_k8s_common/src/test/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreTest.java b/libs/java/server_k8s_common/src/test/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreTest.java new file mode 100644 index 00000000000..0443abcd91e --- /dev/null +++ b/libs/java/server_k8s_common/src/test/java/io/athenz/server/k8s/common/impl/KubernetesSecretPrivateKeyStoreTest.java @@ -0,0 +1,114 @@ +/* + * Copyright The Athenz Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.athenz.server.k8s.common.impl; + +import com.yahoo.athenz.auth.PrivateKeyStore; +import com.yahoo.athenz.auth.ServerPrivateKey; +import io.kubernetes.client.openapi.ApiClient; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.mockito.Mockito; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.Test; + +import java.io.FileInputStream; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.testng.Assert.*; + +public class KubernetesSecretPrivateKeyStoreTest { + private KubernetesSecretPrivateKeyStoreFactory getFactory(final ApiClient k8sClient) { + return new KubernetesSecretPrivateKeyStoreFactory() { + @Override + public PrivateKeyStore create() { + return new KubernetesSecretPrivateKeyStore(k8sClient); + } + }; + } + + private MockWebServer server; + + @Test + public void testGetSecret() throws Exception { + server = new MockWebServer(); + Path path = Paths.get("src/test/resources/sample-secret-response.json"); + try (FileInputStream fis = new FileInputStream(path.toFile())) { + server.enqueue(new MockResponse().setBody(new String(fis.readAllBytes()))); + server.start(); + ApiClient k8sClient = Mockito.spy(new ApiClient()); + HttpUrl baseUrl = server.url("/api/v1/namespaces/myns/secrets/mysecret"); + k8sClient.setBasePath(baseUrl.toString()); + KubernetesSecretPrivateKeyStoreFactory factory = getFactory(k8sClient); + assertEquals(factory.create().getSecret("myns", "mysecret", "password"), new char[]{'c', 'h', 'a', 'n', 'g', 'e', 'i', 't'}); + } + } + + @Test + public void testGetSecretMissing() throws Exception { + server = new MockWebServer(); + Path path = Paths.get("src/test/resources/invalid-secret-key-response.json"); + try (FileInputStream fis = new FileInputStream(path.toFile())) { + server.enqueue(new MockResponse().setBody(new String(fis.readAllBytes()))); + server.start(); + ApiClient k8sClient = Mockito.spy(new ApiClient()); + HttpUrl baseUrl = server.url("/api/v1/namespaces/myns/secrets/mysecret"); + k8sClient.setBasePath(baseUrl.toString()); + KubernetesSecretPrivateKeyStoreFactory factory = getFactory(k8sClient); + assertEquals(factory.create().getSecret("myns", "mysecret", "password"), new char[]{}); + } + } + + @Test + public void testGetPrivateKey() throws Exception { + server = new MockWebServer(); + Path path = Paths.get("src/test/resources/sample-secret-key-response.json"); + byte[] keyBytes; + try (FileInputStream fis = new FileInputStream(path.toFile())) { + keyBytes = fis.readAllBytes(); + //mock response for zms key + server.enqueue(new MockResponse().setBody(new String(keyBytes))); + //mock response for zms key id + server.enqueue(new MockResponse().setBody(new String(keyBytes))); + //mock response for zts key + server.enqueue(new MockResponse().setBody(new String(keyBytes))); + //mock response for zts key id + server.enqueue(new MockResponse().setBody(new String(keyBytes))); + //mock response for msd key + server.enqueue(new MockResponse().setBody(new String(keyBytes))); + //mock response for msd key id + server.enqueue(new MockResponse().setBody(new String(keyBytes))); + server.start(); + ApiClient k8sClient = Mockito.spy(new ApiClient()); + HttpUrl baseUrl = server.url("/api/v1/namespaces/myns/secrets/mysecret"); + k8sClient.setBasePath(baseUrl.toString()); + KubernetesSecretPrivateKeyStoreFactory factory = getFactory(k8sClient); + KubernetesSecretPrivateKeyStore store = (KubernetesSecretPrivateKeyStore) factory.create(); + assertNotNull(store.getPrivateKey("zms", "myns","mysecret", "EC")); + assertNotNull(store.getPrivateKey("zts", "myns","mysecret", "EC")); + assertNotNull(store.getPrivateKey("msd", "myns","mysecret", "EC")); + // no mock response present so expected a read timeout + assertNull(store.getPrivateKey("msd", "myns","mysecret", "EC")); + assertNull(store.getPrivateKey("unknown", "myns","mysecret", "EC")); + } + } + + @AfterMethod + public void tearDown() throws Exception { + server.shutdown(); + } +} \ No newline at end of file diff --git a/libs/java/server_k8s_common/src/test/resources/invalid-secret-key-response.json b/libs/java/server_k8s_common/src/test/resources/invalid-secret-key-response.json new file mode 100644 index 00000000000..7ad2cb1c114 --- /dev/null +++ b/libs/java/server_k8s_common/src/test/resources/invalid-secret-key-response.json @@ -0,0 +1 @@ +{"kind":"Secret","apiVersion":"v1","metadata":{"name":"mysecret","namespace":"myns","uid":"68427c0d-a549-4a44-b938-498d57a541af","resourceVersion":"118061","creationTimestamp":"2024-05-29T20:49:54Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2024-05-29T20:49:54Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:service_k8s_private_key.ec":{}},"f:type":{}}}]},"data":{"service_k8s_private_key.ec":"djAK","service_k8s_private_key_id.ec": "djAK"},"type":"Opaque"} \ No newline at end of file diff --git a/libs/java/server_k8s_common/src/test/resources/sample-secret-key-response.json b/libs/java/server_k8s_common/src/test/resources/sample-secret-key-response.json new file mode 100644 index 00000000000..834c0287efc --- /dev/null +++ b/libs/java/server_k8s_common/src/test/resources/sample-secret-key-response.json @@ -0,0 +1 @@ +{"kind":"Secret","apiVersion":"v1","metadata":{"name":"mysecret","namespace":"myns","uid":"68427c0d-a549-4a44-b938-498d57a541af","resourceVersion":"118061","creationTimestamp":"2024-05-29T20:49:54Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2024-05-29T20:49:54Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:service_k8s_private_key.ec":{}},"f:type":{}}}]},"data":{"service_k8s_private_key.ec":"LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUNQbmFTaGRlY0xyMDViV0I2SnBrTjlGc1FVUndzam5GZkRmNk5VcGo5V0RvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFalRIckFSU1RsUFNHeVZwUHpjTTFYTG12M3hlY2JzY0NOREtlTUt0eDBKNEJOMVhaNXVsNQorb0dXTDlKZG5DOHZmN3M2SVBjeE92SVp0SDdORklWbit3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=","service_k8s_private_key_id.ec": "djAK"},"type":"Opaque"} \ No newline at end of file diff --git a/libs/java/server_k8s_common/src/test/resources/sample-secret-response.json b/libs/java/server_k8s_common/src/test/resources/sample-secret-response.json new file mode 100644 index 00000000000..145cbbc7d48 --- /dev/null +++ b/libs/java/server_k8s_common/src/test/resources/sample-secret-response.json @@ -0,0 +1 @@ +{"kind":"Secret","apiVersion":"v1","metadata":{"name":"mysecret","namespace":"myns","uid":"68427c0d-a549-4a44-b938-498d57a541af","resourceVersion":"118061","creationTimestamp":"2024-05-29T20:49:54Z","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"v1","time":"2024-05-29T20:49:54Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:password":{}},"f:type":{}}}]},"data":{"password":"Y2hhbmdlaXQ="},"type":"Opaque"} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1e64e719f9b..131850a21d5 100644 --- a/pom.xml +++ b/pom.xml @@ -93,11 +93,13 @@ 11.0.21 0.11.5 5.14.0 + 20.0.1 1.2.13 1.5.6 5.12.0 8.4.0 9.39.1 + 4.12.0 1.5.4 1.7.36 2.0.13 @@ -145,6 +147,7 @@ libs/java/client_common libs/java/cert_refresher libs/java/server_common + libs/java/server_k8s_common libs/java/syncer_common libs/java/instance_provider libs/java/dynamodb_client_factory