Skip to content
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

Merged
merged 23 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/publish-azure-cc-enclave-docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ jobs:

- name: Test with Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
if: inputs.publish_vulnerabilities == 'true'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should still scan and fail on critical. We can only publish if it is a public repo, so that is why the switch exists, but we should always scan.
As this is a public repo, i don't think we should even have the publish_vulerabilities switch - we should always scan and publish

Copy link
Contributor Author

@yishi-ttd yishi-ttd Oct 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NVM, got your point. I thought this is a follow up step of the vulnerability check, and depends on previous step's input. But it actually does the same check as Step Generate Trivy vulnerability scan report

Will revert it back.

with:
image-ref: ${{ steps.meta.outputs.tags }}
format: 'table'
Expand Down
23 changes: 18 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@

<groupId>com.uid2</groupId>
<artifactId>uid2-operator</artifactId>
<version>5.18.56-213c024b90</version>

<version>5.18.68-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<vertx.version>4.3.8</vertx.version>
Expand All @@ -18,14 +17,28 @@
<vertx.verticle>com.uid2.operator.vertx.UIDOperatorVerticle</vertx.verticle>
<!-- check micrometer.version vertx-micrometer-metrics consumes before bumping up -->
<micrometer.version>1.1.0</micrometer.version>
<enclave-api.version>1.4.0-e5df2e10aa</enclave-api.version>
<enclave-api.version>1.5.0-676519b018</enclave-api.version>
<enclave-aws.version>1.1.0</enclave-aws.version>
<enclave-azure.version>1.3.0-1246054713</enclave-azure.version>
<enclave-azure.version>1.3.2-SNAPSHOT</enclave-azure.version>
<enclave-gcp.version>1.3.4-649b0b4f7f</enclave-gcp.version>
<uid2-shared.version>5.13.0-a714a3ef26</uid2-shared.version>
<uid2-shared.version>5.13.2-SNAPSHOT</uid2-shared.version>
<image.version>${project.version}</image.version>
</properties>


<repositories>
<repository>
<id>snapshots-repo</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
Expand Down
17 changes: 2 additions & 15 deletions scripts/azure-cc/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#
# This script must be compatible with Ash (provided in eclipse-temurin Docker image) and Bash

# -- set API tokens
if [ -z "${VAULT_NAME}" ]; then
echo "VAULT_NAME cannot be empty"
exit 1
Expand All @@ -13,20 +12,8 @@ if [ -z "${OPERATOR_KEY_SECRET_NAME}" ]; then
exit 1
fi

ACCESS_TOKEN=$(wget "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.net" -q --header "Metadata: true" -O -| jq -e -r ".access_token")
if [ $? -ne 0 -o -z "${ACCESS_TOKEN}" ]; then
echo "Failed to get access token"
exit 1
fi

OPERATOR_KEY=$(wget "https://${VAULT_NAME}.vault.azure.net/secrets/${OPERATOR_KEY_SECRET_NAME}/?api-version=7.4" -q --header "authorization: Bearer ${ACCESS_TOKEN}" --header "content-type: application/json" -O - | jq -e -r ".value")
if [ $? -ne 0 -o -z "${OPERATOR_KEY}" ]; then
echo "Failed to get operator key"
exit 1
fi

export core_api_token="${OPERATOR_KEY}"
export optout_api_token="${OPERATOR_KEY}"
export azure_vault_name="${VAULT_NAME}"
export azure_secret_name="${OPERATOR_KEY_SECRET_NAME}"

# -- locate config file
if [ -z "${DEPLOYMENT_ENVIRONMENT}" ]; then
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/uid2/operator/Const.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ public class Config extends com.uid2.shared.Const.Config {
public static final String SharingTokenExpiryProp = "sharing_token_expiry_seconds";
public static final String EnableClientSideTokenGenerate = "client_side_token_generate";
public static final String ValidateServiceLinks = "validate_service_links";

public static final String AzureVaultNameProp = "azure_vault_name";
public static final String AzureSecretNameProp = "azure_secret_name";

}
}
28 changes: 24 additions & 4 deletions src/main/java/com/uid2/operator/Main.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.uid2.operator;

import ch.qos.logback.classic.LoggerContext;
import com.uid2.enclave.IOperatorKeyRetriever;
import com.uid2.operator.model.KeyManager;
import com.uid2.operator.monitoring.IStatsCollectorQueue;
import com.uid2.operator.monitoring.OperatorMetrics;
import com.uid2.operator.monitoring.StatsCollectorVerticle;
import com.uid2.operator.service.SecureLinkValidatorService;
import com.uid2.operator.store.*;
import com.uid2.operator.store.CloudSyncOptOutStore;
import com.uid2.operator.store.OptOutCloudStorage;
import com.uid2.operator.vertx.OperatorDisableHandler;
import com.uid2.operator.vertx.UIDOperatorVerticle;
import com.uid2.shared.ApplicationVersion;
Expand Down Expand Up @@ -92,13 +94,16 @@ public Main(Vertx vertx, JsonObject config) throws Exception {
this.validateServiceLinks = config.getBoolean(Const.Config.ValidateServiceLinks, false);

String coreAttestUrl = this.config.getString(Const.Config.CoreAttestUrlProp);

var operatorKeyRetriever = createOperatorKeyRetriever();
var operatorKey = operatorKeyRetriever.retrieve();

DownloadCloudStorage fsStores;
if (coreAttestUrl != null) {
String coreApiToken = this.config.getString(Const.Config.CoreApiTokenProp);
Duration disableWaitTime = Duration.ofHours(this.config.getInteger(Const.Config.FailureShutdownWaitHoursProp, 120));
this.disableHandler = new OperatorDisableHandler(disableWaitTime, Clock.systemUTC());

var clients = createUidClients(this.vertx, coreAttestUrl, coreApiToken, this.disableHandler::handleResponseStatus);
var clients = createUidClients(this.vertx, coreAttestUrl, operatorKey, this.disableHandler::handleResponseStatus);
UidCoreClient coreClient = clients.getKey();
UidOptOutClient optOutClient = clients.getValue();
fsStores = coreClient;
Expand Down Expand Up @@ -133,7 +138,7 @@ public Main(Vertx vertx, JsonObject config) throws Exception {
this.keysetProvider = new RotatingKeysetProvider(fsStores, new GlobalScope(new CloudPath(keysetMdPath)));
String saltsMdPath = this.config.getString(Const.Config.SaltsMetadataPathProp);
this.saltProvider = new RotatingSaltProvider(fsStores, saltsMdPath);
this.optOutStore = new CloudSyncOptOutStore(vertx, fsLocal, this.config);
this.optOutStore = new CloudSyncOptOutStore(vertx, fsLocal, this.config, operatorKey);

if (this.validateServiceLinks) {
String serviceMdPath = this.config.getString(Const.Config.ServiceMetadataPathProp);
Expand Down Expand Up @@ -484,4 +489,19 @@ private Map.Entry<UidCoreClient, UidOptOutClient> createUidClients(Vertx vertx,
UidOptOutClient optOutClient = new UidOptOutClient(clientApiToken, CloudUtils.defaultProxy, enforceHttps, attestationTokenRetriever);
return new AbstractMap.SimpleEntry<>(coreClient, optOutClient);
}

private IOperatorKeyRetriever createOperatorKeyRetriever() throws Exception {
var enclavePlatform = this.config.getString("enclave_platform", "");
yishi-ttd marked this conversation as resolved.
Show resolved Hide resolved
switch (enclavePlatform) {
case "azure-cc": {
var vaultName = this.config.getString(Const.Config.AzureVaultNameProp);
var secretName = this.config.getString(Const.Config.AzureSecretNameProp);
return OperatorKeyRetrieverFactory.getAzureOperatorKeyRetriever(vaultName, secretName);
}
default: {
// default to load from config
return () -> this.config.getString(Const.Config.CoreApiTokenProp);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L55 is a different config.
Currently we will set the same operator key for both "OptOutApiToken" and "CoreApiToken".

The value of "OptOutApiToken" should also be fetched from vault - actually it's just operator key.

Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

@yishi-ttd yishi-ttd Oct 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will remove OptOutApiTokenProp config first in this PR.
This is the only place that will use it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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;
Expand Down