Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ variables to adjust the application to your needs:
|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
| AUTH_JWKS_URL | URL to retrieve a JWKS for verifying JWTs. | |
| HUB_AUTH_BASE_URL | Base URL to reach the Hub's core component. | |
| HUB_AUTH_ROBOT_ID | Robot ID associated with the node. | |
| HUB_AUTH_ROBOT_SECRET_FILE | Path to the file containing the secret of the node's associated robot account, as plain text. | |
| HUB_AUTH_CLIENT_ID | Client ID associated with the node. | |
| HUB_AUTH_CLIENT_SECRET_FILE | Path to the file containing the secret of the node's associated client account, as plain text. | |
| HUB_BASE_URL | Base URL to reach the Hub's auth component. | |
| HUB_MESSENGER_BASE_URL | Base URL to reach the Hub's messenger component. | |
| LOG_LEVEL | Log level being used. Can be either of `trace`, `debug`, `info`, `warn` or `error`. | `info` |
Expand Down
4 changes: 2 additions & 2 deletions cert-showcase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ _The hub services will NEVER be requested!_

1. Ensure having a registered node with a public/private key configured (__do not use the one you would use for
production!__)
2. Copy the node's robot secret to `./config/secrets/robot-secret-node.txt`
2. Copy the node's client secret to `./config/secrets/client-secret-node.txt`
3. Copy the node's private key to `./config/secrets/priv-key-node.pem`
4. (Optional) Remove trailing newlines from the two files by running

```shell
truncate -s -1 ./config/secrets/robot-secret-node.txt ./config/secrets/priv-key-node.pem
truncate -s -1 ./config/secrets/client-secret-node.txt ./config/secrets/priv-key-node.pem
```

5. Create self-signed certificates by running `./create-cert.sh`
Expand Down
10 changes: 5 additions & 5 deletions cert-showcase/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ services:
restart: always
secrets:
- priv-key-node.pem
- robot-secret-node.txt
- client-secret-node.txt
# The following does NOT work in temurin since they are using a 2-step process which
# itself alters system resources and thus requires root permission.
#volumes:
Expand All @@ -62,8 +62,8 @@ services:
environment:
AUTH_JWKS_URL: "http://localhost:18080/realms/privateaim/protocol/openid-connect/certs"
HUB_AUTH_BASE_URL: "https://auth.privateaim.internal"
HUB_AUTH_ROBOT_ID: "ce84b6a8-df3d-451b-8411-4fb57570c47a"
HUB_AUTH_ROBOT_SECRET_FILE: /run/secrets/robot-secret-node.txt
HUB_AUTH_CLIENT_ID: "ce84b6a8-df3d-451b-8411-4fb57570c47a"
HUB_AUTH_CLIENT_SECRET_FILE: /run/secrets/client-secret-node.txt
HUB_BASE_URL: "https://core.privateaim.internal"
HUB_MESSENGER_BASE_URL: "https://messenger.privateaim.internal"
SECURITY_NODE_PRIVATE_ECDH_KEY_FILE: /run/secrets/priv-key-node.pem
Expand Down Expand Up @@ -103,5 +103,5 @@ services:
secrets:
priv-key-node.pem:
file: ./config/secrets/priv-key-node.pem
robot-secret-node.txt:
file: ./config/secrets/robot-secret-node.txt
client-secret-node.txt:
file: ./config/secrets/client-secret-node.txt
4 changes: 2 additions & 2 deletions k8s/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ make sure the following environment variables are set:
| ENV VAR | DESCRIPTION |
|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
| AUTH_JWKS_URL | URL to obtain JWKS from. Using keycloak this has the pattern `<KEYCLOAK_BASE_URL>/realms/<YOUR_REALM>/protocol/openid-connect/certs`. |
| HUB_AUTH_ROBOT_ID | ID of the robot account to be used. Needs to exist on the central side (hub) at `https://auth.privateaim.dev/`. |
| ROBOT_SECRET | Associated secret of the robot account. |
| HUB_AUTH_CLIENT_ID | ID of the client account to be used. Needs to exist on the central side (hub) at `https://auth.privateaim.dev/`. |
| CLIENT_SECRET | Associated secret of the client account. |
| NODE_PRIVATE_KEY | Private key of the node in PEM format. |
| NODE_MESSAGE_BROKER_HOST | Host to be used for the message broker. It will be accessible under `message-broker.<HOST>.nip.io`. |
| NAMESPACE | Namespace to be used within the minikube cluster. |
Expand Down
14 changes: 7 additions & 7 deletions k8s/deploy-to-minikube.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Mandatory environment variables:
#
# - AUTH_JWKS_URL
# - HUB_AUTH_ROBOT_ID
# - ROBOT_SECRET
# - HUB_AUTH_CLIENT_ID
# - CLIENT_SECRET
# - NODE_PRIVATE_KEY
# - NODE_MESSAGE_BROKER_HOST
# - NAMESPACE
Expand All @@ -17,13 +17,13 @@

BASE_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 || exit 1 ; pwd -P )"

if [[ -z "${AUTH_JWKS_URL}" || -z "${HUB_AUTH_ROBOT_ID}" || -z "${ROBOT_SECRET}" || -z "${NODE_PRIVATE_KEY}" || -z "${NODE_MESSAGE_BROKER_HOST}" || -z "${NAMESPACE}" ]]; then
if [[ -z "${AUTH_JWKS_URL}" || -z "${HUB_AUTH_CLIENT_ID}" || -z "${CLIENT_SECRET}" || -z "${NODE_PRIVATE_KEY}" || -z "${NODE_MESSAGE_BROKER_HOST}" || -z "${NAMESPACE}" ]]; then
echo "One or more mandatory environment variables are not set!"
echo "Mandatory environment variables are:"
echo ""
echo " - AUTH_JWKS_URL"
echo " - HUB_AUTH_ROBOT_ID"
echo " - ROBOT_SECRET"
echo " - HUB_AUTH_CLIENT_ID"
echo " - CLIENT_SECRET"
echo " - NODE_PRIVATE_KEY"
echo " - NODE_MESSAGE_BROKER_HOST"
echo " - NAMESPACE"
Expand Down Expand Up @@ -51,15 +51,15 @@ checkSuccessOrFailWithCode $? 3

echo -n "Preparing broker deployment..."
sed -i -e "s#<AUTH_JWKS_URL>#${AUTH_JWKS_URL}#" \
-e "s#<HUB_AUTH_ROBOT_ID>#${HUB_AUTH_ROBOT_ID}#" \
-e "s#<HUB_AUTH_CLIENT_ID>#${HUB_AUTH_CLIENT_ID}#" \
-e "s#<HUB_AUTH_BASE_URL>#${HUB_AUTH_BASE_URL:-"https://auth.privateaim.dev"}#" \
-e "s#<HUB_BASE_URL>#${HUB_BASE_URL:-"https://core.privateaim.dev"}#" \
-e "s#<HUB_MESSENGER_BASE_URL>#${HUB_MESSENGER_BASE_URL:-"https://messenger.privateaim.dev"}#" \
"${WORK_DIR}/broker-deployment.yml"
checkSuccessOrFailWithCode $? 4

echo -n "Preparing hub auth secret..."
sed -i -e "s#<ROBOT_SECRET>#${ROBOT_SECRET}#" \
sed -i -e "s#<CLIENT_SECRET>#${CLIENT_SECRET}#" \
"${WORK_DIR}/hub-auth-secret.yml"
checkSuccessOrFailWithCode $? 5

Expand Down
20 changes: 10 additions & 10 deletions k8s/manifests/broker-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ spec:
value: <HUB_BASE_URL>
- name: HUB_AUTH_BASE_URL
value: <HUB_AUTH_BASE_URL>
- name: HUB_AUTH_ROBOT_ID
value: <HUB_AUTH_ROBOT_ID>
- name: HUB_AUTH_ROBOT_SECRET_FILE
value: "/tmp/robot-secret.txt"
- name: HUB_AUTH_CLIENT_ID
value: <HUB_AUTH_CLIENT_ID>
- name: HUB_AUTH_CLIENT_SECRET_FILE
value: "/tmp/client-secret.txt"
- name: SECURITY_NODE_PRIVATE_ECDH_KEY_FILE
value: "/tmp/private-key.pem"
volumeMounts:
- mountPath: "/tmp/private-key.pem"
name: private-key-file
subPath: node-private-key
readOnly: true
- mountPath: "/tmp/robot-secret.txt"
name: robot-secret-file
subPath: robot-secret
- mountPath: "/tmp/client-secret.txt"
name: client-secret-file
subPath: client-secret
readOnly: true
resources:
requests:
Expand Down Expand Up @@ -89,10 +89,10 @@ spec:
items:
- key: node-private-key
path: node-private-key
- name: robot-secret-file
- name: client-secret-file
secret:
secretName: hub-auth
items:
- key: robot-secret
path: robot-secret
- key: client-secret
path: client-secret

2 changes: 1 addition & 1 deletion k8s/manifests/hub-auth-secret.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ kind: Secret
metadata:
name: hub-auth
data:
robot-secret: <ROBOT_SECRET>
client-secret: <CLIENT_SECRET>
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ public class CommonSpringConfig {
@Value("${app.hub.auth.baseUrl}")
private String hubAuthBaseUrl;

@Value("${app.hub.auth.robotId}")
private String hubAuthRobotId;
@Value("${app.hub.auth.clientId}")
private String hubAuthClientId;

@Value("${app.hub.auth.robotSecretFile}")
private String hubAuthRobotSecretFile;
@Value("${app.hub.auth.clientSecretFile}")
private String hubAuthClientSecretFile;

@Value("${app.proxy.host}")
private String proxyHost;
Expand All @@ -62,16 +62,16 @@ public class CommonSpringConfig {
@Value("${app.proxy.passwordFile}")
private String proxyPasswordFile;

@Qualifier("HUB_AUTH_ROBOT_SECRET")
@Qualifier("HUB_AUTH_CLIENT_SECRET")
@Bean
public String hubAuthRobotSecret() throws IOException {
return new String(ConfigurationUtil.readExternalFileContent(hubAuthRobotSecretFile));
return new String(ConfigurationUtil.readExternalFileContent(hubAuthClientSecretFile));
}

@Qualifier("HUB_AUTH_ROBOT_ID")
@Qualifier("HUB_AUTH_CLIENT_ID")
@Bean
public String hubAuthRobotId() {
return hubAuthRobotId;
public String hubAuthClientId() {
return hubAuthClientId;
}

@Qualifier("HUB_EXCHANGE_RETRY_CONFIG")
Expand Down Expand Up @@ -194,14 +194,14 @@ ObjectMapper simpleJsonMapper() {
OIDCAuthenticator hubAuthenticator(
@Qualifier("HUB_AUTH_WEB_CLIENT") WebClient webClient,
@Qualifier("HUB_EXCHANGE_RETRY_CONFIG") HttpRetryConfig retryConfig,
@Qualifier("HUB_AUTH_ROBOT_ID") String hubAuthRobotId,
@Qualifier("HUB_AUTH_ROBOT_SECRET") String hubAuthRobotSecret,
@Qualifier("HUB_AUTH_CLIENT_ID") String hubAuthClientId,
@Qualifier("HUB_AUTH_CLIENT_SECRET") String hubAuthRobotSecret,
@Qualifier("HUB_JSON_MAPPER") ObjectMapper jsonMapper
) {
return HubOIDCAuthenticator.builder()
.usingWebClient(webClient)
.withRetryConfig(retryConfig)
.withAuthCredentials(hubAuthRobotId, hubAuthRobotSecret)
.withAuthCredentials(hubAuthClientId, hubAuthRobotSecret)
.withJsonDecoder(jsonMapper)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,33 +70,33 @@ public Mono<List<AnalysisNode>> fetchAnalysisNodes(String analysisId) {

// TODO: add cache here! - see spring annotations
@Override
public Mono<ECPublicKey> fetchPublicKey(String robotId) {
public Mono<ECPublicKey> fetchPublicKey(String clientId) {
return authenticatedWebClient.get()
.uri(uriBuilder -> uriBuilder
.path("/nodes")
.queryParam("filter[robot_id]", robotId)
.queryParam("filter[client_id]", clientId)
.build()
)
.retrieve()
.onStatus(HttpStatusCode::is5xxServerError,
response -> {
var err = new HubCoreServerException(("could not fetch public key for node with robot id" +
" `%s` from hub").formatted(robotId));
var err = new HubCoreServerException(("could not fetch public key for node with client id" +
" `%s` from hub").formatted(clientId));

log.warn("retrying to request public key for node with robot id `{}` from hub after" +
" failed attempt", robotId, err);
log.warn("retrying to request public key for node with client id `{}` from hub after" +
" failed attempt", clientId, err);
return Mono.error(err);
})
.bodyToMono(new ParameterizedTypeReference<HubResponseContainer<List<Node>>>() {
})
.flatMap(resp -> {
if (resp.data.size() != 1) {
return Mono.error(new NoMatchingNodeFoundException("cannot find node with robot id `%s`"
.formatted(robotId)));
return Mono.error(new NoMatchingNodeFoundException("cannot find node with client id `%s`"
.formatted(clientId)));
}
if (resp.data.getFirst().publicKey == null) {
return Mono.error(new NoPublicKeyException("node with robot id `%s` has no public key set"
.formatted(robotId)));
return Mono.error(new NoPublicKeyException("node with client id `%s` has no public key set"
.formatted(clientId)));
}
return Mono.just(Hex.decode(resp.data.getFirst().publicKey.getBytes()));
})
Expand All @@ -108,7 +108,7 @@ public Mono<ECPublicKey> fetchPublicKey(String robotId) {
return Mono.just((ECPublicKey) new JcaPEMKeyConverter().getPublicKey(key));
} catch (IOException e) {
return Mono.error(new MalformedPublicKeyException("failed to read public key from node with " +
"robot id `%s`".formatted(robotId), e));
"client id `%s`".formatted(clientId), e));
}
})
.retryWhen(Retry.backoff(retryConfig.maxRetries(), Duration.ofMillis(retryConfig.retryDelayMs()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public interface HubClient {
/**
* Fetches the public key of a node identified by its ID.
*
* @param nodeRobotId unique identifier of a node's robot
* @param nodeClientId unique identifier of a node's client
* @return The node's public key.
*/
Mono<ECPublicKey> fetchPublicKey(String nodeRobotId);
Mono<ECPublicKey> fetchPublicKey(String nodeClientId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ public final class Node {
@JsonProperty("public_key")
public String publicKey;

@JsonProperty("robot_id")
public String robotId;
@JsonProperty("client_id")
public String clientId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public final class HubOIDCAuthenticator implements OIDCAuthenticator {
private final String clientSecret;

private static final String TOKEN_PATH = "/token";
private static final String GRANT_TYPE_AUTHENTICATE = "robot_credentials";
private static final String GRANT_TYPE_AUTHENTICATE = "client_credentials";
private static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";

private static final String JWT_CLAIM__ISSUED_AT = "iat";
Expand All @@ -61,8 +61,8 @@ public Mono<OIDCTokenPair> authenticate() {
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.accept(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromFormData("grant_type", GRANT_TYPE_AUTHENTICATE)
.with("id", clientId)
.with("secret", clientSecret))
.with("client_id", clientId)
.with("client_secret", clientSecret))
.retrieve()
.onStatus(HttpStatusCode::is5xxServerError,
response -> Mono.error(new HubAuthException("could not fetch hub access token")))
Expand Down
Loading
Loading