-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Load azure secret from vault in JAVA code #254
Changes from 4 commits
7a5464a
91fd594
144b0d2
2637d64
ebfd9f5
9c66795
0c52f3d
9daad39
270eff0
c047263
147fbc6
f502e35
07c64a4
33fe6d3
1969c7f
7762ef8
69577b4
d866607
ab1775c
b364d9c
7923d18
ea47ea1
2c404d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package com.uid2.operator.operatorkey; | ||
|
||
import com.azure.identity.ManagedIdentityCredentialBuilder; | ||
import com.azure.security.keyvault.secrets.SecretClientBuilder; | ||
import com.google.common.base.Strings; | ||
import com.uid2.operator.Const; | ||
import io.vertx.core.json.JsonObject; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class AzureVaultOperatorKeyRetriever implements IOperatorKeyRetriever { | ||
private static final Logger LOGGER = LoggerFactory.getLogger(AzureVaultOperatorKeyRetriever.class); | ||
private final JsonObject config; | ||
|
||
public AzureVaultOperatorKeyRetriever(JsonObject config) { | ||
this.config = config; | ||
} | ||
|
||
@Override | ||
public String retrieve() { | ||
// Check API token field first, if it's specified, use it. | ||
var tokenValue = this.config.getString(Const.Config.CoreApiTokenProp); | ||
|
||
if (!Strings.isNullOrEmpty(tokenValue)) { | ||
return tokenValue; | ||
} | ||
|
||
// Otherwise, try to load it from vault. | ||
var vaultName = this.config.getString(Const.Config.AzureVaultNameProp); | ||
if (Strings.isNullOrEmpty(vaultName)) { | ||
throw new IllegalArgumentException(Const.Config.AzureVaultNameProp + " is null or empty"); | ||
} | ||
|
||
var secretName = this.config.getString(Const.Config.AzureSecretNameProp); | ||
if (Strings.isNullOrEmpty(secretName)) { | ||
throw new IllegalArgumentException(Const.Config.AzureSecretNameProp + " is null or empty"); | ||
} | ||
|
||
return retrieveFromAzure(vaultName, secretName); | ||
} | ||
|
||
// ManagedIdentityCredential is used here. | ||
private String retrieveFromAzure(String vaultName, String secretName) { | ||
String vaultUrl = "https://" + vaultName + ".vault.azure.net"; | ||
LOGGER.info(String.format("Load OperatorKey secret (%s) from %s", secretName, vaultUrl)); | ||
// Use default ExponentialBackoff retry policy | ||
var secretClient = new SecretClientBuilder() | ||
.vaultUrl(vaultUrl) | ||
.credential(new ManagedIdentityCredentialBuilder().build()) | ||
.buildClient(); | ||
|
||
var retrievedSecret = secretClient.getSecret(secretName); | ||
|
||
LOGGER.info("OperatorKey secret is loaded."); | ||
return retrievedSecret.getValue(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.uid2.operator.operatorkey; | ||
|
||
import com.uid2.operator.Const; | ||
import io.vertx.core.json.JsonObject; | ||
|
||
public class ConfigOperatorKeyRetriever implements IOperatorKeyRetriever { | ||
private final JsonObject config; | ||
|
||
public ConfigOperatorKeyRetriever(JsonObject config) { | ||
this.config = config; | ||
} | ||
|
||
@Override | ||
public String retrieve() { | ||
return this.config.getString(Const.Config.CoreApiTokenProp); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.uid2.operator.operatorkey; | ||
|
||
public interface IOperatorKeyRetriever { | ||
public String retrieve(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.uid2.operator.operatorkey; | ||
|
||
import io.vertx.core.json.JsonObject; | ||
|
||
public class OperatorKeyRetrieverFactory { | ||
public static IOperatorKeyRetriever getOperatorKeyRetriever(JsonObject config) { | ||
String enclavePlatform = config.getString("enclave_platform", ""); | ||
switch (enclavePlatform) { | ||
case "azure-cc": | ||
return new AzureVaultOperatorKeyRetriever(config); | ||
default: | ||
return new ConfigOperatorKeyRetriever(config); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,11 +19,11 @@ | |
import io.vertx.core.Handler; | ||
import io.vertx.core.Vertx; | ||
import io.vertx.core.json.JsonObject; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import io.vertx.ext.web.client.HttpResponse; | ||
import io.vertx.ext.web.client.WebClient; | ||
import io.vertx.ext.web.codec.BodyCodec; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
@@ -48,7 +48,7 @@ public class CloudSyncOptOutStore implements IOptOutStore { | |
private final String remoteApiPath; | ||
private final String remoteApiBearerToken; | ||
|
||
public CloudSyncOptOutStore(Vertx vertx, ICloudStorage fsLocal, JsonObject jsonConfig) throws MalformedURLException { | ||
public CloudSyncOptOutStore(Vertx vertx, ICloudStorage fsLocal, JsonObject jsonConfig, String operatorKey) throws MalformedURLException { | ||
this.fsLocal = fsLocal; | ||
this.webClient = WebClient.create(vertx); | ||
|
||
|
@@ -58,7 +58,7 @@ public CloudSyncOptOutStore(Vertx vertx, ICloudStorage fsLocal, JsonObject jsonC | |
this.remoteApiPort = -1 == url.getPort() ? 80 : url.getPort(); | ||
this.remoteApiHost = url.getHost(); | ||
this.remoteApiPath = url.getPath(); | ||
this.remoteApiBearerToken = "Bearer " + jsonConfig.getString(Const.Config.OptOutApiTokenProp); | ||
this.remoteApiBearerToken = "Bearer " + operatorKey; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we changing this? It is also used directly above on line 55 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. L55 is a different config. The value of "OptOutApiToken" should also be fetched from vault - actually it's just operator key. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, but this would mean we are actually getting rid of the config setting for optout_api_token. In that case, we need to remove it from the code, and from all the config. This could be another ticket, but I don't think we should leave unused config settings in the code / config files There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will remove OptOutApiTokenProp config first in this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As for the places to set this env, I will create a ticket to track. |
||
} else { | ||
this.remoteApiPort = -1; | ||
this.remoteApiHost = null; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.uid2.operator.operatorkey; | ||
|
||
import com.uid2.operator.Const; | ||
import io.vertx.core.json.JsonObject; | ||
import org.junit.Assert; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
class AzureVaultOperatorKeyRetrieverTest { | ||
@Test | ||
public void testReturnApiTokenIfSpecified() { | ||
var OPERATOR_KEY = "operator_key"; | ||
var config = new JsonObject().put(Const.Config.CoreApiTokenProp, OPERATOR_KEY); | ||
|
||
var sut = new AzureVaultOperatorKeyRetriever(config); | ||
var key = sut.retrieve(); | ||
|
||
assertEquals(OPERATOR_KEY, key); | ||
} | ||
|
||
@Test | ||
public void testArgumentCheck_NoVaultName() { | ||
var config = new JsonObject(); | ||
|
||
var sut = new AzureVaultOperatorKeyRetriever(config); | ||
Assert.assertThrows(IllegalArgumentException.class, () -> sut.retrieve()); | ||
} | ||
|
||
@Test | ||
public void testArgumentCheck_NoSecretName() { | ||
var config = new JsonObject().put(Const.Config.AzureVaultNameProp, "dummy"); | ||
|
||
var sut = new AzureVaultOperatorKeyRetriever(config); | ||
Assert.assertThrows(IllegalArgumentException.class, () -> sut.retrieve()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name of the property and the class name difference will cause confusion - the OperatorKeyRetriever reads the CoreApiTokenProp? They should both be called OperatorKey or CoreApiToken
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CoreApiTokenProp(core_api_token) is an existing config in shared and I don't want to change this to break existing logic.
E.g. currently AWS/GCP will set
core_api_token
andoptout_api_token
, they could still work after this change.