From ac23039c0d8b6bd28b4cc380744128db00b8af08 Mon Sep 17 00:00:00 2001 From: George Kitsos Date: Fri, 15 Mar 2024 13:29:55 +0200 Subject: [PATCH] Initial Commit Change-Id: Iec38321b67ec1171d492b31b43ffed58ffabcbb2 --- .../Chart.yaml | 5 + .../templates/deployment.yaml | 38 ++- .../templates/service.yaml | 10 +- .../values.yaml | 19 +- java-spring-boot-demo/Dockerfile | 15 - java-spring-boot-demo/pom.xml | 42 --- .../com/example/demo/DemoApplication.java | 13 - .../java/com/example/demo/DemoController.java | 14 - .../src/main/resources/application.properties | 0 .../example/demo/DemoApplicationTests.java | 13 - network-manager/.env.example | 11 + .../.gitignore | 3 + network-manager/.m2/settings.xml | 18 + network-manager/.mvn/wrapper/.gitignore | 1 + .../.mvn/wrapper/MavenWrapperDownloader.java | 142 ++++++++ .../.mvn/wrapper/maven-wrapper.properties | 18 + network-manager/Dockerfile | 43 +++ network-manager/README.md | 85 +++++ .../casbin-k8s-gatekeeper.sh | 52 +++ .../create-k8s-node.sh | 70 ++++ .../create-master-k8s-node.sh | 27 ++ .../create-worker-k8s-node.sh | 11 + network-manager/mvnw | 316 ++++++++++++++++++ network-manager/mvnw.cmd | 188 +++++++++++ network-manager/pom.xml | 210 ++++++++++++ .../src/main/java/Application.java | 31 ++ .../eu/nebulous/dto/ApplicationNodeDto.java | 10 + .../src/main/java/eu/nebulous/dto/LogDto.java | 20 ++ .../java/eu/nebulous/enums/StatusEnum.java | 16 + .../exception/BadRequestAlertException.java | 17 + .../InternalServerErrorException.java | 19 ++ .../exception/NotFoundAlertException.java | 19 ++ .../nebulous/model/ApplicationMasterNode.java | 50 +++ .../nebulous/model/ApplicationWorkerNode.java | 48 +++ .../ApplicationMasterNodeRepository.java | 13 + .../ApplicationWorkerNodeRepository.java | 20 ++ .../eu/nebulous/resource/ApiResource.java | 20 ++ .../resource/ApplicationNodeResource.java | 46 +++ .../eu/nebulous/resource/GatewayResource.java | 19 ++ .../service/ApplicationNodeService.java | 289 ++++++++++++++++ .../java/eu/nebulous/service/LogService.java | 24 ++ .../service/RemoteCodeExecutionService.java | 135 ++++++++ .../service/SSHKeyPairGeneratorService.java | 82 +++++ .../service/WGKeyPairGeneratorService.java | 50 +++ .../src/main/java/eu/nebulous/util/Util.java | 26 ++ .../src/main/resources/application.yml | 39 +++ .../client/README.md | 7 + .../client/wg-client-create_client.sh | 40 +++ .../client/wg-client-create_server.sh | 64 ++++ .../client/wg-client-delete_client.sh | 35 ++ .../client/wg-client-delete_server.sh | 25 ++ .../nm-bootstrap-script.sh | 60 ++++ .../server/README.md | 7 + .../server/wg-server-create.sh | 54 +++ .../server/wg-server-delete.sh | 28 ++ zuul.d/jobs.yaml | 10 +- 56 files changed, 2571 insertions(+), 116 deletions(-) delete mode 100644 java-spring-boot-demo/Dockerfile delete mode 100644 java-spring-boot-demo/pom.xml delete mode 100644 java-spring-boot-demo/src/main/java/com/example/demo/DemoApplication.java delete mode 100644 java-spring-boot-demo/src/main/java/com/example/demo/DemoController.java delete mode 100644 java-spring-boot-demo/src/main/resources/application.properties delete mode 100644 java-spring-boot-demo/src/test/java/com/example/demo/DemoApplicationTests.java create mode 100644 network-manager/.env.example rename {java-spring-boot-demo => network-manager}/.gitignore (93%) create mode 100644 network-manager/.m2/settings.xml create mode 100644 network-manager/.mvn/wrapper/.gitignore create mode 100644 network-manager/.mvn/wrapper/MavenWrapperDownloader.java create mode 100644 network-manager/.mvn/wrapper/maven-wrapper.properties create mode 100644 network-manager/Dockerfile create mode 100644 network-manager/README.md create mode 100644 network-manager/k8s-bootstrap-agent-scripts/casbin-k8s-gatekeeper.sh create mode 100644 network-manager/k8s-bootstrap-agent-scripts/create-k8s-node.sh create mode 100644 network-manager/k8s-bootstrap-agent-scripts/create-master-k8s-node.sh create mode 100644 network-manager/k8s-bootstrap-agent-scripts/create-worker-k8s-node.sh create mode 100755 network-manager/mvnw create mode 100644 network-manager/mvnw.cmd create mode 100644 network-manager/pom.xml create mode 100644 network-manager/src/main/java/Application.java create mode 100644 network-manager/src/main/java/eu/nebulous/dto/ApplicationNodeDto.java create mode 100644 network-manager/src/main/java/eu/nebulous/dto/LogDto.java create mode 100644 network-manager/src/main/java/eu/nebulous/enums/StatusEnum.java create mode 100644 network-manager/src/main/java/eu/nebulous/exception/BadRequestAlertException.java create mode 100644 network-manager/src/main/java/eu/nebulous/exception/InternalServerErrorException.java create mode 100644 network-manager/src/main/java/eu/nebulous/exception/NotFoundAlertException.java create mode 100644 network-manager/src/main/java/eu/nebulous/model/ApplicationMasterNode.java create mode 100644 network-manager/src/main/java/eu/nebulous/model/ApplicationWorkerNode.java create mode 100644 network-manager/src/main/java/eu/nebulous/repository/ApplicationMasterNodeRepository.java create mode 100644 network-manager/src/main/java/eu/nebulous/repository/ApplicationWorkerNodeRepository.java create mode 100644 network-manager/src/main/java/eu/nebulous/resource/ApiResource.java create mode 100644 network-manager/src/main/java/eu/nebulous/resource/ApplicationNodeResource.java create mode 100644 network-manager/src/main/java/eu/nebulous/resource/GatewayResource.java create mode 100644 network-manager/src/main/java/eu/nebulous/service/ApplicationNodeService.java create mode 100644 network-manager/src/main/java/eu/nebulous/service/LogService.java create mode 100644 network-manager/src/main/java/eu/nebulous/service/RemoteCodeExecutionService.java create mode 100644 network-manager/src/main/java/eu/nebulous/service/SSHKeyPairGeneratorService.java create mode 100644 network-manager/src/main/java/eu/nebulous/service/WGKeyPairGeneratorService.java create mode 100644 network-manager/src/main/java/eu/nebulous/util/Util.java create mode 100644 network-manager/src/main/resources/application.yml create mode 100644 network-manager/wg-bootstrap-agent-scripts/client/README.md create mode 100644 network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_client.sh create mode 100644 network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_server.sh create mode 100644 network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_client.sh create mode 100644 network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_server.sh create mode 100755 network-manager/wg-bootstrap-agent-scripts/nm-bootstrap-script.sh create mode 100644 network-manager/wg-bootstrap-agent-scripts/server/README.md create mode 100644 network-manager/wg-bootstrap-agent-scripts/server/wg-server-create.sh create mode 100644 network-manager/wg-bootstrap-agent-scripts/server/wg-server-delete.sh diff --git a/charts/nebulous-overlay-network-manager/Chart.yaml b/charts/nebulous-overlay-network-manager/Chart.yaml index 60a4c5f..6b8b804 100644 --- a/charts/nebulous-overlay-network-manager/Chart.yaml +++ b/charts/nebulous-overlay-network-manager/Chart.yaml @@ -22,3 +22,8 @@ version: 0.1.0 # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. appVersion: "latest" + +dependencies: + - name: postgresql + version: 14.3.3 + repository: https://charts.bitnami.com/bitnami diff --git a/charts/nebulous-overlay-network-manager/templates/deployment.yaml b/charts/nebulous-overlay-network-manager/templates/deployment.yaml index 3234152..5aac584 100644 --- a/charts/nebulous-overlay-network-manager/templates/deployment.yaml +++ b/charts/nebulous-overlay-network-manager/templates/deployment.yaml @@ -27,6 +27,10 @@ spec: serviceAccountName: {{ include "nebulous-overlay-network-manager.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + - name: wait-for-postgresql + image: docker.io/bitnami/postgresql:14.3.0 + command: ['sh', '-c', 'until pg_isready -h nebulous-overlay-network-manager-postgresql -p 5432; do echo waiting for database; sleep 2; done;'] containers: - name: {{ .Chart.Name }} securityContext: @@ -34,19 +38,33 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - name: http - containerPort: 8080 + - name: onm-api + containerPort: 8082 + protocol: TCP + - name: pgadmin + containerPort: 5050 protocol: TCP - livenessProbe: - httpGet: - path: / - port: http - readinessProbe: - httpGet: - path: / - port: http resources: {{- toYaml .Values.resources | nindent 12 }} + env: + - name: POSTGRES_USER + value: {{ .Values.postgresql.global.postgresql.auth.username }} + - name: POSTGRES_PASSWORD + value: {{ .Values.postgresql.global.postgresql.auth.password }} + - name: POSTGRES_DB + value: {{ .Values.postgresql.global.postgresql.auth.database }} + - name: POSTGRES_IP_FQDN + value: "nebulous-overlay-network-manager-postgresql" + - name: POSTGRES_CONNECTION_STRING + value: "jdbc:postgresql://nebulous-overlay-network-manager-postgresql:5432/postgres" + - name: WIREGUARD_NETWORK_PORTION + value: "{{ .Values.customEnv.WIREGUARD_NETWORK_PORTION }}" + - name: WIREGUARD_DEFAULT_SERVER_IP + value: "{{ .Values.customEnv.WIREGUARD_DEFAULT_SERVER_IP }}" + - name: WIREGUARD_ALLOWED_IPS + value: "{{ .Values.customEnv.WIREGUARD_ALLOWED_IPS }}" + - name: _PROD_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR + value: "{{ .Values.customEnv._PROD_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR }}" {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/nebulous-overlay-network-manager/templates/service.yaml b/charts/nebulous-overlay-network-manager/templates/service.yaml index 4e60fb7..dd4ebf8 100644 --- a/charts/nebulous-overlay-network-manager/templates/service.yaml +++ b/charts/nebulous-overlay-network-manager/templates/service.yaml @@ -7,9 +7,13 @@ metadata: spec: type: {{ .Values.service.type }} ports: - - port: {{ .Values.service.port }} - targetPort: http + - port: {{ .Values.service.pgadminPort }} + targetPort: pgadmin protocol: TCP - name: http + name: pgadmin + - port: {{ .Values.service.onmApiPort }} + targetPort: onm-api + protocol: TCP + name: onm-api selector: {{- include "nebulous-overlay-network-manager.selectorLabels" . | nindent 4 }} diff --git a/charts/nebulous-overlay-network-manager/values.yaml b/charts/nebulous-overlay-network-manager/values.yaml index 089db9c..ef4b70f 100644 --- a/charts/nebulous-overlay-network-manager/values.yaml +++ b/charts/nebulous-overlay-network-manager/values.yaml @@ -5,7 +5,7 @@ replicaCount: 1 image: - repository: "quay.io/nebulous/overlay-network-manager-java-spring-boot-demo" + repository: "quay.io/nebulous/overlay-network-manager" pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. tag: "" @@ -39,6 +39,8 @@ securityContext: {} service: type: ClusterIP port: 80 + pgadminPort: 5050 + onmApiPort: 8082 ingress: enabled: false @@ -80,3 +82,18 @@ nodeSelector: {} tolerations: [] affinity: {} + +postgresql: + global: + postgresql: + auth: + postgresPassword: "nebulous" + username: "postgresql" + password: "postgresql" + database: "postgres" + +customEnv: + WIREGUARD_NETWORK_PORTION: "192.168.55." + WIREGUARD_DEFAULT_SERVER_IP: "192.168.55.1" + WIREGUARD_ALLOWED_IPS: "192.168.55.0/24" + _PROD_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR: "/deployments/wg-bootstrap-agent-scripts" diff --git a/java-spring-boot-demo/Dockerfile b/java-spring-boot-demo/Dockerfile deleted file mode 100644 index 427e30e..0000000 --- a/java-spring-boot-demo/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Build stage -# -FROM docker.io/library/maven:3.9.2-eclipse-temurin-17 AS build -COPY src /home/app/src -COPY pom.xml /home/app -RUN mvn -f /home/app/pom.xml clean package - -# -# Package stage -# -FROM docker.io/library/eclipse-temurin:17-jre -COPY --from=build /home/app/target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo.jar -EXPOSE 8080 -ENTRYPOINT ["java","-jar","/usr/local/lib/demo.jar"] diff --git a/java-spring-boot-demo/pom.xml b/java-spring-boot-demo/pom.xml deleted file mode 100644 index 76e0f0e..0000000 --- a/java-spring-boot-demo/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 3.1.0 - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - 17 - - - - org.springframework.boot - spring-boot-starter - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - diff --git a/java-spring-boot-demo/src/main/java/com/example/demo/DemoApplication.java b/java-spring-boot-demo/src/main/java/com/example/demo/DemoApplication.java deleted file mode 100644 index 094d95b..0000000 --- a/java-spring-boot-demo/src/main/java/com/example/demo/DemoApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class DemoApplication { - - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } - -} diff --git a/java-spring-boot-demo/src/main/java/com/example/demo/DemoController.java b/java-spring-boot-demo/src/main/java/com/example/demo/DemoController.java deleted file mode 100644 index 61a5075..0000000 --- a/java-spring-boot-demo/src/main/java/com/example/demo/DemoController.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo; - -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class DemoController { - - @RequestMapping("/") - public Object root() { - return null; - } - -} diff --git a/java-spring-boot-demo/src/main/resources/application.properties b/java-spring-boot-demo/src/main/resources/application.properties deleted file mode 100644 index e69de29..0000000 diff --git a/java-spring-boot-demo/src/test/java/com/example/demo/DemoApplicationTests.java b/java-spring-boot-demo/src/test/java/com/example/demo/DemoApplicationTests.java deleted file mode 100644 index eaa9969..0000000 --- a/java-spring-boot-demo/src/test/java/com/example/demo/DemoApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.demo; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class DemoApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/network-manager/.env.example b/network-manager/.env.example new file mode 100644 index 0000000..cd585e1 --- /dev/null +++ b/network-manager/.env.example @@ -0,0 +1,11 @@ +PC_IP_ADDRESS= + +POSTGRES_CONNECTION_STRING= +POSTGRES_USER= +POSTGRES_PASSWORD= + +WIREGUARD_NETWORK_PORTION= +WIREGUARD_DEFAULT_SERVER_IP= +WIREGUARD_ALLOWED_IPS= +_DEV_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR= +_PROD_WG_BOOTSTRAP_AGENT_SCRIPTS_DIR= \ No newline at end of file diff --git a/java-spring-boot-demo/.gitignore b/network-manager/.gitignore similarity index 93% rename from java-spring-boot-demo/.gitignore rename to network-manager/.gitignore index 549e00a..551797c 100644 --- a/java-spring-boot-demo/.gitignore +++ b/network-manager/.gitignore @@ -31,3 +31,6 @@ build/ ### VS Code ### .vscode/ + +# Local environment +.env diff --git a/network-manager/.m2/settings.xml b/network-manager/.m2/settings.xml new file mode 100644 index 0000000..8e97b73 --- /dev/null +++ b/network-manager/.m2/settings.xml @@ -0,0 +1,18 @@ + + + + quarkus-base-no-auth + + + + Job-Token + ${CI_JOB_TOKEN} + + + + + + diff --git a/network-manager/.mvn/wrapper/.gitignore b/network-manager/.mvn/wrapper/.gitignore new file mode 100644 index 0000000..e72f5e8 --- /dev/null +++ b/network-manager/.mvn/wrapper/.gitignore @@ -0,0 +1 @@ +maven-wrapper.jar diff --git a/network-manager/.mvn/wrapper/MavenWrapperDownloader.java b/network-manager/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..1708393 --- /dev/null +++ b/network-manager/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader +{ + private static final String WRAPPER_VERSION = "3.1.1"; + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/" + WRAPPER_VERSION + + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use instead of the + * default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main( String args[] ) + { + System.out.println( "- Downloader started" ); + File baseDirectory = new File( args[0] ); + System.out.println( "- Using base directory: " + baseDirectory.getAbsolutePath() ); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File( baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH ); + String url = DEFAULT_DOWNLOAD_URL; + if ( mavenWrapperPropertyFile.exists() ) + { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try + { + mavenWrapperPropertyFileInputStream = new FileInputStream( mavenWrapperPropertyFile ); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load( mavenWrapperPropertyFileInputStream ); + url = mavenWrapperProperties.getProperty( PROPERTY_NAME_WRAPPER_URL, url ); + } + catch ( IOException e ) + { + System.out.println( "- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'" ); + } + finally + { + try + { + if ( mavenWrapperPropertyFileInputStream != null ) + { + mavenWrapperPropertyFileInputStream.close(); + } + } + catch ( IOException e ) + { + // Ignore ... + } + } + } + System.out.println( "- Downloading from: " + url ); + + File outputFile = new File( baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH ); + if ( !outputFile.getParentFile().exists() ) + { + if ( !outputFile.getParentFile().mkdirs() ) + { + System.out.println( "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + + "'" ); + } + } + System.out.println( "- Downloading to: " + outputFile.getAbsolutePath() ); + try + { + downloadFileFromURL( url, outputFile ); + System.out.println( "Done" ); + System.exit( 0 ); + } + catch ( Throwable e ) + { + System.out.println( "- Error downloading" ); + e.printStackTrace(); + System.exit( 1 ); + } + } + + private static void downloadFileFromURL( String urlString, File destination ) + throws Exception + { + if ( System.getenv( "MVNW_USERNAME" ) != null && System.getenv( "MVNW_PASSWORD" ) != null ) + { + String username = System.getenv( "MVNW_USERNAME" ); + char[] password = System.getenv( "MVNW_PASSWORD" ).toCharArray(); + Authenticator.setDefault( new Authenticator() + { + @Override + protected PasswordAuthentication getPasswordAuthentication() + { + return new PasswordAuthentication( username, password ); + } + } ); + } + URL website = new URL( urlString ); + ReadableByteChannel rbc; + rbc = Channels.newChannel( website.openStream() ); + FileOutputStream fos = new FileOutputStream( destination ); + fos.getChannel().transferFrom( rbc, 0, Long.MAX_VALUE ); + fos.close(); + rbc.close(); + } + +} diff --git a/network-manager/.mvn/wrapper/maven-wrapper.properties b/network-manager/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..61a2ef1 --- /dev/null +++ b/network-manager/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/network-manager/Dockerfile b/network-manager/Dockerfile new file mode 100644 index 0000000..a5a4d39 --- /dev/null +++ b/network-manager/Dockerfile @@ -0,0 +1,43 @@ +FROM docker.io/curlimages/curl:8.5.0 AS downloader +ARG RUN_JAVA_VERSION=1.3.5 +RUN curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /tmp/run-java.sh + +FROM docker.io/maven:3.9.1-eclipse-temurin-20 AS build + +WORKDIR /app +COPY src ./src +COPY wg-bootstrap-agent-scripts ./wg-bootstrap-agent-scripts +COPY pom.xml ./ + +RUN mvn clean package -DskipTests + +FROM docker.io/eclipse-temurin:20-jre-alpine + +ENV USER_ID=1001 + +RUN mkdir /deployments \ + && chown ${USER_ID} /deployments \ + && chmod "g+rwX" /deployments \ + && chown 1001:root /deployments + +COPY --from=downloader /tmp/run-java.sh /deployments/run-java.sh + +RUN chown ${USER_ID} /deployments/run-java.sh && chmod 540 /deployments/run-java.sh + +# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8090" +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' + +# Copy the built artifact from the maven image +COPY --from=build /app/target/*-runner.jar /deployments/app.jar + +# Copy scripts from build Dockerfile step +COPY --from=build /app/wg-bootstrap-agent-scripts /deployments/wg-bootstrap-agent-scripts + +EXPOSE 8080 +EXPOSE 8090 + +USER ${USER_ID} + +ENTRYPOINT [ "/deployments/run-java.sh" ] \ No newline at end of file diff --git a/network-manager/README.md b/network-manager/README.md new file mode 100644 index 0000000..888146a --- /dev/null +++ b/network-manager/README.md @@ -0,0 +1,85 @@ +# Overlay Network Manager + +## Provided Services + +This is a template project, providing the bare minimum in order to build a Quarkus Service. +To be more precise, it includes: +1. Swagger UI with OpenAPI Specification + +## Technology Stack + +This project uses Quarkus, the Supersonic Subatomic Java Framework. + +If you want to learn more about Quarkus, please visit its website: https://quarkus.io/. + +Moreover, the core services used, alongside with their versions, are: +1. Quarkus **3.2.7.Final** +2. Java **20** + +## Environmental Variables + +There is a .env.example file containing all the appropriate information. + +## Swagger/OpenAPI Services +These are accessible through the following paths: +1. Swagger UI: http://localhost:8080/api/swagger +2. OpenAPI Specification: http://localhost:8080/api/openapi + +## Running the application in dev mode + +You can run your application in dev mode that enables live coding using: +```shell script +./mvnw compile quarkus:dev +``` +> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/. + +## Packaging and running the application + +The application can be packaged using: +```shell script +./mvnw package +``` +It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory. +Be aware that it’s not a _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory. + +The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. + +If you want to build a _über-jar_, execute the following command: +```shell script +./mvnw package -Dquarkus.package.type=uber-jar +``` + +The application, packaged as a _über-jar_, is now runnable using `java -jar target/*-runner.jar`. + +## Creating a native executable + +You can create a native executable using: +```shell script +./mvnw package -Pnative +``` + +Or, if you don't have GraalVM installed, you can run the native executable build in a container using: +```shell script +./mvnw package -Pnative -Dquarkus.native.container-build=true +``` + +You can then execute your native executable with: `./target/getting-started-1.0.0-SNAPSHOT-runner` + +If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling. + +Run the docker image using: +```shell script +docker run -i --env-file .env --rm -p 8080:8080 +``` + +## Related Guides + +- RESTEasy Reactive ([guide](https://quarkus.io/guides/resteasy-reactive)): A JAX-RS implementation utilizing build time processing and Vert.x. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it. + +## Provided Code + +### RESTEasy Reactive + +Easily start your Reactive RESTful Web Services + +[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources) diff --git a/network-manager/k8s-bootstrap-agent-scripts/casbin-k8s-gatekeeper.sh b/network-manager/k8s-bootstrap-agent-scripts/casbin-k8s-gatekeeper.sh new file mode 100644 index 0000000..7877912 --- /dev/null +++ b/network-manager/k8s-bootstrap-agent-scripts/casbin-k8s-gatekeeper.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Define the original and the copy paths for the kubeconfig file +ORIGINAL_KUBECONFIG_PATH="$HOME/.kube/config" +KUBECONFIG_COPY_PATH="$HOME/.kube/config-copy" + +# Copy the original kubeconfig file to a new location +if [ -f "$ORIGINAL_KUBECONFIG_PATH" ]; then + cp "$ORIGINAL_KUBECONFIG_PATH" "$KUBECONFIG_COPY_PATH" + echo "Kubeconfig file copied to $KUBECONFIG_COPY_PATH." +else + echo "Original kubeconfig file not found at $ORIGINAL_KUBECONFIG_PATH." + exit 1 +fi + +# Create the configmap from the copied kubeconfig file +kubectl create configmap kubeconfig --from-file=config=$KUBECONFIG_COPY_PATH +if [ $? -eq 0 ]; then + echo "ConfigMap created successfully." +else + echo "Failed to create ConfigMap." + exit 1 +fi + +# Directory to store the YAML files +REPO_URL="https://gitlab.ubitech.eu/nebulous/use-cases/k8s-gatekeeper/-/raw/origin/config" + +# Create the directory if it doesn't exist +CONFIG_DIR=$HOME/k8s/config +mkdir -p $CONFIG_DIR + +# List of configuration files to download +CONFIG_FILES="rbac.yaml webhook_deployment.yaml webhook_internal.yaml auth.casbin.org_casbinmodels.yaml auth.casbin.org_casbinpolicies.yaml" + +# Download the configuration files +for file in $CONFIG_FILES; do + echo "WGET file: $file" + wget -O "$CONFIG_DIR/$file" "$REPO_URL/$file" + if [ $? -ne 0 ]; then + echo "Failed to download $file." + exit 1 + fi +done + +# apply the downloaded configurations with delay +DELAY=5 +for file in $CONFIG_FILES; do + kubectl apply -f "$CONFIG_DIR/$file" + sleep $DELAY +done + +echo "All configurations applied successfully." \ No newline at end of file diff --git a/network-manager/k8s-bootstrap-agent-scripts/create-k8s-node.sh b/network-manager/k8s-bootstrap-agent-scripts/create-k8s-node.sh new file mode 100644 index 0000000..e248d79 --- /dev/null +++ b/network-manager/k8s-bootstrap-agent-scripts/create-k8s-node.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +# Capture the second argument as the hostname +HOSTNAME=$1 +# Set the hostname +echo "Setting hostname to '$HOSTNAME'..." +sudo hostnamectl set-hostname "$HOSTNAME" + +WIREGUARD_VPN_IP=`ip a | grep wg | grep inet | awk '{print $2}' | cut -d'/' -f1` + +# Create k8s directory to host all appropriate files +mkdir -p $HOME/k8s + +# Update Repository +sudo DEBIAN_FRONTEND=noninteractive apt update + +# Install libraries +sudo DEBIAN_FRONTEND=noninteractive apt install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common + +# Docker Keys +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg +echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + +# Update Repositories again +sudo DEBIAN_FRONTEND=noninteractive apt update + +# Install Docker +sudo DEBIAN_FRONTEND=noninteractive apt install -y docker-ce=5:20.10.22~3-0~ubuntu-jammy docker-ce-cli=5:20.10.22~3-0~ubuntu-jammy containerd.io=1.6.14-1 +sudo usermod -aG docker $USER +sudo systemctl enable docker +sudo systemctl start docker +cat < /dev/null + +# Update Repositories +sudo DEBIAN_FRONTEND=noninteractive apt-get update + +# Install K8s CLI tools +sudo DEBIAN_FRONTEND=noninteractive apt-get install -y kubeadm=1.22.4-00 kubelet=1.22.4-00 kubectl=1.22.4-00 +sudo DEBIAN_FRONTEND=noninteractive apt-mark hold kubeadm kubelet kubectl +echo "KUBELET_EXTRA_ARGS=--node-ip=${WIREGUARD_VPN_IP}" | sudo tee -a /etc/default/kubelet +sudo systemctl restart kubelet + +# Disable Swap +sudo swapoff -a +sudo sed -i '/ swap / s/^/#/' /etc/fstab + +# Set hostname label to K8s Node +sudo kubectl label nodes "$HOSTNAME" disktype=ssd + +# Install Helm Package Manager +curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 +sudo chmod 700 get_helm.sh +sudo $HOME/get_helm.sh + +echo "Configuration complete." diff --git a/network-manager/k8s-bootstrap-agent-scripts/create-master-k8s-node.sh b/network-manager/k8s-bootstrap-agent-scripts/create-master-k8s-node.sh new file mode 100644 index 0000000..ca9c6c6 --- /dev/null +++ b/network-manager/k8s-bootstrap-agent-scripts/create-master-k8s-node.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +WIREGUARD_VPN_IP=`ip a | grep wg | grep inet | awk '{print $2}' | cut -d'/' -f1` + +# Init kubernetes +sudo kubeadm init --apiserver-advertise-address ${WIREGUARD_VPN_IP} --service-cidr 10.96.0.0/16 --pod-network-cidr 10.244.0.0/16 + +# Set kubeconfig file +mkdir -p $HOME/.kube +sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config +sudo chown $(id -u):$(id -g) $HOME/.kube/config + +# Add Cilium Helm Repo +helm repo add cilium https://helm.cilium.io/ +helm repo update + +# Install Cilium with Wireguard parameters +helm install cilium cilium/cilium --namespace kube-system --set encryption.enabled=true --set encryption.type=wireguard + +# Add KubeVela Helm repository and update +echo "Setting up KubeVela..." +helm repo add kubevela https://kubevelacharts.oss-cn-hangzhou.aliyuncs.com/core +helm repo update +helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wait + +# Save join command to specific path for the worker nodes to SCP +kubeadm token create --print-join-command > $HOME/k8s-join-command.sh \ No newline at end of file diff --git a/network-manager/k8s-bootstrap-agent-scripts/create-worker-k8s-node.sh b/network-manager/k8s-bootstrap-agent-scripts/create-worker-k8s-node.sh new file mode 100644 index 0000000..3ae67dd --- /dev/null +++ b/network-manager/k8s-bootstrap-agent-scripts/create-worker-k8s-node.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +MASTER_IP=$1 +MASTER_USERNAME=$2 + +# Join Kubernetes Cluster +sudo scp -o StrictHostKeyChecking=no -i $HOME/wg-private-key.key $MASTER_USERNAME@$MASTER_IP:/home/$MASTER_USERNAME/k8s-join-command.sh /home/$USER/k8s/k8s-join-command.sh + +sudo chmod +x $HOME/k8s/k8s-join-command.sh + +sudo $HOME/k8s/k8s-join-command.sh diff --git a/network-manager/mvnw b/network-manager/mvnw new file mode 100755 index 0000000..eaa3d30 --- /dev/null +++ b/network-manager/mvnw @@ -0,0 +1,316 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 +# +# https://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/network-manager/mvnw.cmd b/network-manager/mvnw.cmd new file mode 100644 index 0000000..abb7c32 --- /dev/null +++ b/network-manager/mvnw.cmd @@ -0,0 +1,188 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/network-manager/pom.xml b/network-manager/pom.xml new file mode 100644 index 0000000..efaec7a --- /dev/null +++ b/network-manager/pom.xml @@ -0,0 +1,210 @@ + + + 4.0.0 + eu.nebulous + network-manager + 1.0.0 + + + 3.11.0 + 17 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 3.2.7.Final + + true + + 3.0.0 + + ${quarkus.platform.group-id} + ${quarkus.platform.version} + + 1.18.24 + + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + ${quarkus.qpid.jms.group-id} + quarkus-qpid-jms-bom + ${quarkus.qpid.jms.version} + pom + import + + + + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-resteasy-jackson + + + io.quarkus + quarkus-arc + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + io.quarkus + quarkus-smallrye-openapi + + + io.quarkus + quarkus-smallrye-health + + + + com.google.code.gson + gson + 2.10.1 + + + + io.quarkus + quarkus-config-yaml + + + + io.quarkus + quarkus-hibernate-validator + + + io.quarkus + quarkus-hibernate-orm-panache + + + + io.quarkus + quarkus-jdbc-postgresql + + + + org.bouncycastle + bcprov-jdk18on + 1.76 + + + org.bouncycastle + bcpkix-jdk15on + 1.70 + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + org.apache.sshd + sshd-core + 2.11.0 + + + org.apache.sshd + sshd-common + 2.11.0 + + + org.apache.sshd + sshd-scp + 2.11.0 + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + + native + + + native + + + + false + native + + + + diff --git a/network-manager/src/main/java/Application.java b/network-manager/src/main/java/Application.java new file mode 100644 index 0000000..f421b6c --- /dev/null +++ b/network-manager/src/main/java/Application.java @@ -0,0 +1,31 @@ +import io.quarkus.runtime.ShutdownEvent; +import io.quarkus.runtime.StartupEvent; +import io.quarkus.runtime.configuration.ProfileManager; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; + +import java.time.ZoneId; +import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; + +@ApplicationScoped +public class Application { + + private static final Logger logger = Logger.getLogger(Application.class.getName()); + + public Application() { + // Empty Constructor + } + + void onStart(@Observes StartupEvent ev) { + logger.info("The application is starting..."); + logger.log(Level.INFO,"Default timezone: {0} with id {1}", new Object[]{TimeZone.getDefault().getDisplayName(), ZoneId.systemDefault()}); + var profile = ProfileManager.getLaunchMode(); + logger.log(Level.INFO,"Running profile: {0}", profile); + } + + void onStop(@Observes ShutdownEvent ev) { + logger.info("The application is stopping..."); + } +} diff --git a/network-manager/src/main/java/eu/nebulous/dto/ApplicationNodeDto.java b/network-manager/src/main/java/eu/nebulous/dto/ApplicationNodeDto.java new file mode 100644 index 0000000..4108da7 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/dto/ApplicationNodeDto.java @@ -0,0 +1,10 @@ +package eu.nebulous.dto; + +public record ApplicationNodeDto( + String publicIp, + String applicationUUID, + Boolean isMaster, + String sshUsername, + String privateKeyBase64, + String publicKey +) {} diff --git a/network-manager/src/main/java/eu/nebulous/dto/LogDto.java b/network-manager/src/main/java/eu/nebulous/dto/LogDto.java new file mode 100644 index 0000000..8eb2411 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/dto/LogDto.java @@ -0,0 +1,20 @@ +package eu.nebulous.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.Date; +import java.util.logging.Level; + +@EqualsAndHashCode(callSuper = false) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LogDto { + private Date date; + private Level logLevel; + private String title; + private String message; +} diff --git a/network-manager/src/main/java/eu/nebulous/enums/StatusEnum.java b/network-manager/src/main/java/eu/nebulous/enums/StatusEnum.java new file mode 100644 index 0000000..3911cd0 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/enums/StatusEnum.java @@ -0,0 +1,16 @@ +package eu.nebulous.enums; +public enum StatusEnum { + + SUCCESS("Success"), + FAILURE("Failure"); + + private final String description; + + StatusEnum(String description) { + this.description = description; + } + + public String getDescription() { + return this.description; + } +} diff --git a/network-manager/src/main/java/eu/nebulous/exception/BadRequestAlertException.java b/network-manager/src/main/java/eu/nebulous/exception/BadRequestAlertException.java new file mode 100644 index 0000000..aeee323 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/exception/BadRequestAlertException.java @@ -0,0 +1,17 @@ +package eu.nebulous.exception; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +import java.io.Serial; + +import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; + +public class BadRequestAlertException extends WebApplicationException { + @Serial + private static final long serialVersionUID = 1L; + + public BadRequestAlertException(String message, String entityName, String errorKey) { + super(Response.status(BAD_REQUEST).entity(message).header("message", "error." + errorKey).header("params", entityName).build()); + } +} diff --git a/network-manager/src/main/java/eu/nebulous/exception/InternalServerErrorException.java b/network-manager/src/main/java/eu/nebulous/exception/InternalServerErrorException.java new file mode 100644 index 0000000..68c3a20 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/exception/InternalServerErrorException.java @@ -0,0 +1,19 @@ +package eu.nebulous.exception; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +import java.io.Serial; + +public class InternalServerErrorException extends WebApplicationException { + @Serial + private static final long serialVersionUID = 1L; + + public InternalServerErrorException() { + this("HTTP 500 - Internal server error. Please contact site admin."); + } + + public InternalServerErrorException(String message) { + super(Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(message).build()); + } +} \ No newline at end of file diff --git a/network-manager/src/main/java/eu/nebulous/exception/NotFoundAlertException.java b/network-manager/src/main/java/eu/nebulous/exception/NotFoundAlertException.java new file mode 100644 index 0000000..a70743e --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/exception/NotFoundAlertException.java @@ -0,0 +1,19 @@ +package eu.nebulous.exception; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response; + +import java.io.Serial; + +import static jakarta.ws.rs.core.Response.Status.NOT_FOUND; + +public class NotFoundAlertException extends WebApplicationException { + @Serial + private static final long serialVersionUID = 1L; + + public NotFoundAlertException(String entityName) { + super(Response.status(NOT_FOUND).entity("Entity " + entityName + "was not found") + .header("message", "error." + "notfound") + .header("params", entityName).build()); + } +} diff --git a/network-manager/src/main/java/eu/nebulous/model/ApplicationMasterNode.java b/network-manager/src/main/java/eu/nebulous/model/ApplicationMasterNode.java new file mode 100644 index 0000000..135468c --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/model/ApplicationMasterNode.java @@ -0,0 +1,50 @@ +package eu.nebulous.model; + +import io.quarkus.hibernate.orm.panache.PanacheEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@Entity +@EqualsAndHashCode(callSuper = false) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ApplicationMasterNode extends PanacheEntity { + private String uuid; + + @Column(name = "publicIp") + private String publicIp; + + @Column(name = "applicationUUID") + private String applicationUUID; + + @Column(name = "sshUsername") + private String sshUsername; + + @Column(length = 5000, name = "openSSLPrivateKey") + private String openSSLPrivateKey; + + @Column(length = 1000, name = "openSSLPublicKey") + private String openSSLPublicKey; + + @Column(name = "wireguardPrivateKey") + private String wireguardPrivateKey; + + @Column(name = "wireguardPublicKey") + private String wireguardPublicKey; + + @Column(name = "wireguardOverlaySubnet") + private String wireguardOverlaySubnet; + + @Column(name = "wireguardIp") + private String wireguardIp; + + @Column(name = "dateCreated") + private Date dateCreated; +} diff --git a/network-manager/src/main/java/eu/nebulous/model/ApplicationWorkerNode.java b/network-manager/src/main/java/eu/nebulous/model/ApplicationWorkerNode.java new file mode 100644 index 0000000..df51d34 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/model/ApplicationWorkerNode.java @@ -0,0 +1,48 @@ +package eu.nebulous.model; + +import io.quarkus.hibernate.orm.panache.PanacheEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.ManyToOne; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@Entity +@EqualsAndHashCode(callSuper = false) +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ApplicationWorkerNode extends PanacheEntity { + private String uuid; + + @Column(name = "publicIp") + private String publicIp; + + @Column(name = "sshUsername") + private String sshUsername; + + @Column(name = "wireguardPrivateKey") + private String wireguardPrivateKey; + + @Column(name = "wireguardPublicKey") + private String wireguardPublicKey; + + @Column(length = 5000, name = "openSSLPrivateKey") + private String openSSLPrivateKey; + + @Column(length = 1000, name = "openSSLPublicKey") + private String openSSLPublicKey; + + @Column(name = "dateCreated") + private Date dateCreated; + + @Column(name = "wireguardIp") + private String wireguardIp; + + @ManyToOne + public ApplicationMasterNode applicationMasterNode; +} diff --git a/network-manager/src/main/java/eu/nebulous/repository/ApplicationMasterNodeRepository.java b/network-manager/src/main/java/eu/nebulous/repository/ApplicationMasterNodeRepository.java new file mode 100644 index 0000000..3d1fb07 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/repository/ApplicationMasterNodeRepository.java @@ -0,0 +1,13 @@ +package eu.nebulous.repository; + +import eu.nebulous.model.ApplicationMasterNode; +import io.quarkus.hibernate.orm.panache.PanacheRepository; +import jakarta.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ApplicationMasterNodeRepository implements PanacheRepository { + + public ApplicationMasterNode findByApplicationUUID(String applicationUUID){ + return find("applicationUUID", applicationUUID).firstResult(); + } +} diff --git a/network-manager/src/main/java/eu/nebulous/repository/ApplicationWorkerNodeRepository.java b/network-manager/src/main/java/eu/nebulous/repository/ApplicationWorkerNodeRepository.java new file mode 100644 index 0000000..6a20a7d --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/repository/ApplicationWorkerNodeRepository.java @@ -0,0 +1,20 @@ +package eu.nebulous.repository; + +import eu.nebulous.dto.ApplicationNodeDto; +import eu.nebulous.model.ApplicationMasterNode; +import eu.nebulous.model.ApplicationWorkerNode; +import io.quarkus.hibernate.orm.panache.PanacheRepository; +import jakarta.enterprise.context.ApplicationScoped; + +import java.util.List; + +@ApplicationScoped +public class ApplicationWorkerNodeRepository implements PanacheRepository { + public List findWorkerNodesByMasterNode(ApplicationMasterNode masterNode){ + return find("applicationMasterNode", masterNode).list(); + } + + public ApplicationWorkerNode findWorkerByPublicIp(ApplicationNodeDto applicationNodeDto){ + return find("publicIp", applicationNodeDto.publicIp()).firstResult(); + } +} diff --git a/network-manager/src/main/java/eu/nebulous/resource/ApiResource.java b/network-manager/src/main/java/eu/nebulous/resource/ApiResource.java new file mode 100644 index 0000000..738360a --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/resource/ApiResource.java @@ -0,0 +1,20 @@ +package eu.nebulous.resource; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.Path; + +@Singleton +public class ApiResource { + private final ApplicationNodeResource applicationNodeResource; + + @Inject + public ApiResource(ApplicationNodeResource applicationNodeResource) { + this.applicationNodeResource = applicationNodeResource; + } + + @Path("/node") + public ApplicationNodeResource getAuthResource() { + return applicationNodeResource; + } +} diff --git a/network-manager/src/main/java/eu/nebulous/resource/ApplicationNodeResource.java b/network-manager/src/main/java/eu/nebulous/resource/ApplicationNodeResource.java new file mode 100644 index 0000000..758fd14 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/resource/ApplicationNodeResource.java @@ -0,0 +1,46 @@ +package eu.nebulous.resource; + +import eu.nebulous.dto.ApplicationNodeDto; +import eu.nebulous.service.ApplicationNodeService; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.validation.Valid; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.tags.Tag; + +@Singleton +public class ApplicationNodeResource { + + @Inject + ApplicationNodeService applicationNodeService; + + @POST + @Path("/create") + @Tag(name = "Application Node") + @Consumes(MediaType.APPLICATION_JSON) + @Operation(summary = "Add Application Node to Application Cluster") + public Response addApplicationNode(@Valid ApplicationNodeDto applicationNodeDto) { + // Create Configuration for Application Node + var logs = applicationNodeService.evaluateNodeCreation(applicationNodeDto); + + return Response.ok(logs).build(); + } + + @DELETE + @Path("/delete") + @Tag(name = "Application Node") + @Consumes(MediaType.APPLICATION_JSON) + @Operation(summary = "Delete Application Node From Application Cluster") + public Response deleteApplicationNode(@Valid ApplicationNodeDto applicationNodeDto) { + // Create Configuration for Application Node + var logs = applicationNodeService.evaluateNodeDeletion(applicationNodeDto); + + return Response.ok(logs).build(); + } +} diff --git a/network-manager/src/main/java/eu/nebulous/resource/GatewayResource.java b/network-manager/src/main/java/eu/nebulous/resource/GatewayResource.java new file mode 100644 index 0000000..0689856 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/resource/GatewayResource.java @@ -0,0 +1,19 @@ +package eu.nebulous.resource; + +import jakarta.inject.Inject; +import jakarta.ws.rs.Path; + +@Path("/") +public class GatewayResource { + private final ApiResource apiResource; + + @Inject + public GatewayResource(ApiResource apiResource) { + this.apiResource = apiResource; + } + + @Path("/api/v1") + public ApiResource getApiResource() { + return apiResource; + } +} \ No newline at end of file diff --git a/network-manager/src/main/java/eu/nebulous/service/ApplicationNodeService.java b/network-manager/src/main/java/eu/nebulous/service/ApplicationNodeService.java new file mode 100644 index 0000000..3db5e38 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/service/ApplicationNodeService.java @@ -0,0 +1,289 @@ +package eu.nebulous.service; + +import eu.nebulous.dto.ApplicationNodeDto; +import eu.nebulous.dto.LogDto; +import eu.nebulous.model.ApplicationMasterNode; +import eu.nebulous.model.ApplicationWorkerNode; +import eu.nebulous.repository.ApplicationMasterNodeRepository; +import eu.nebulous.repository.ApplicationWorkerNodeRepository; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; + +@ApplicationScoped +public class ApplicationNodeService { + @Inject + ApplicationMasterNodeRepository applicationMasterNodeRepository; + + @Inject + ApplicationWorkerNodeRepository applicationWorkerNodeRepository; + + @Inject + WGKeyPairGeneratorService wgKeyPairGeneratorService; + + @Inject + RemoteCodeExecutionService remoteCodeExecutionService; + + @Inject + LogService logService; + + @ConfigProperty(name = "WIREGUARD_ALLOWED_IPS") + String wireguardAllowedIps; + + @ConfigProperty(name = "WIREGUARD_DEFAULT_SERVER_IP") + String wireguardDefaultServerIp; + + @ConfigProperty(name = "WIREGUARD_NETWORK_PORTION") + String wireguardNetworkPortion; + + @ConfigProperty(name = "WG_BOOTSTRAP_AGENT_SCRIPTS_DIR") + String wgBootstrapAgentScriptsDir; + + private static final String ONM = "ONM"; + + private void persistApplicationMasterNode(List logList, ApplicationNodeDto applicationNodeDto, String openSSLPrivateKey, String openSSLPublicKey, + String wireguardPrivateKey, String wireguardPublicKey) { + try { + var applicationMasterNode = new ApplicationMasterNode(); + applicationMasterNode.setUuid(UUID.randomUUID().toString()); + applicationMasterNode.setPublicIp(applicationNodeDto.publicIp()); + applicationMasterNode.setApplicationUUID(applicationNodeDto.applicationUUID()); + applicationMasterNode.setSshUsername(applicationNodeDto.sshUsername()); + applicationMasterNode.setDateCreated(new Date()); + applicationMasterNode.setOpenSSLPrivateKey(openSSLPrivateKey); + applicationMasterNode.setOpenSSLPublicKey(openSSLPublicKey); + applicationMasterNode.setWireguardPrivateKey(wireguardPrivateKey); + applicationMasterNode.setWireguardPublicKey(wireguardPublicKey); + applicationMasterNode.setWireguardOverlaySubnet(wireguardAllowedIps); + applicationMasterNode.setWireguardIp(wireguardDefaultServerIp); + + applicationMasterNodeRepository.persist(applicationMasterNode); + + logService.log(logList, Level.INFO, ONM, "SUCCESS -> Application Node Master (" + applicationNodeDto.publicIp() + + "," + applicationNodeDto.applicationUUID() + ") successfully persisted to DB!"); + } catch (Exception e) { + logService.log(logList, Level.WARNING, ONM, "FAILURE -> The Application Node Master (" + applicationNodeDto.publicIp() + + "," + applicationNodeDto.applicationUUID() + ") failed to be persisted to DB!"); + } + } + + private void persistApplicationWorkerNode(List logList, ApplicationNodeDto applicationNodeDto, ApplicationMasterNode masterNode, + String wireguardPrivateKey, String wireguardPublicKey, String wireguardWorkerIp) { + try { + var applicationWorkerNode = new ApplicationWorkerNode(); + applicationWorkerNode.setUuid(UUID.randomUUID().toString()); + applicationWorkerNode.setSshUsername(applicationNodeDto.sshUsername()); + applicationWorkerNode.setPublicIp(applicationNodeDto.publicIp()); + applicationWorkerNode.setApplicationMasterNode(masterNode); + applicationWorkerNode.setDateCreated(new Date()); + applicationWorkerNode.setWireguardPrivateKey(wireguardPrivateKey); + applicationWorkerNode.setWireguardPublicKey(wireguardPublicKey); + applicationWorkerNode.setWireguardIp(wireguardWorkerIp); + applicationWorkerNode.setOpenSSLPrivateKey(applicationNodeDto.privateKeyBase64()); + applicationWorkerNode.setOpenSSLPublicKey(applicationNodeDto.publicKey()); + + applicationWorkerNodeRepository.persist(applicationWorkerNode); + + logService.log(logList, Level.INFO, ONM, "SUCCESS -> Application Node Worker (" + applicationNodeDto.publicIp() + + "," + applicationNodeDto.applicationUUID() + ") successfully persisted to DB!"); + } catch (Exception e) { + logService.log(logList, Level.WARNING, ONM, "FAILURE -> The Application Node Worker (" + applicationNodeDto.publicIp() + + "," + applicationNodeDto.applicationUUID() + ") failed to be persisted to DB!"); + } + } + + @Transactional + public List evaluateNodeCreation(ApplicationNodeDto applicationNodeDto) { + var logList = new ArrayList(); + + // Create WG Key Pair Function + var wireguardKeyPair = wgKeyPairGeneratorService.createWireguardKeyPair(applicationNodeDto.publicIp()); + var wireguardPrivateKey = wireguardKeyPair.get("private"); + var wireguardPublicKey = wireguardKeyPair.get("public"); + + logService.log(logList, Level.INFO, ONM, "Created WG Key Pair for Application Node with Public IP: " + applicationNodeDto.publicIp()); + + if (applicationNodeDto.isMaster().equals(Boolean.TRUE)) { + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-server-create.sh ------------------------------------"); + logService.log(logList, Level.INFO, ONM, "SCP FILE wg-server-create.sh to HOST: " + applicationNodeDto.publicIp()); + + remoteCodeExecutionService.scpFile(applicationNodeDto.sshUsername(),applicationNodeDto.publicIp(), + 22,applicationNodeDto.privateKeyBase64(),30L, + wgBootstrapAgentScriptsDir + "/server/wg-server-create.sh", + "wireguard",null); + logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-server-create.sh to HOST: " + applicationNodeDto.publicIp()); + + var permissionsCommand = "sudo chmod +x /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-server-create.sh"; + var executeCommand = "sudo /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-server-create.sh " + wireguardPrivateKey + " " + + wireguardPublicKey + " " + " " + wireguardDefaultServerIp; + remoteCodeExecutionService.runCommand(applicationNodeDto.sshUsername(),applicationNodeDto.privateKeyBase64(),applicationNodeDto.publicIp(), + 22,30L, + permissionsCommand + ";" + executeCommand, null); + logService.log(logList, Level.INFO, ONM, "COMMAND wg-server-create.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!"); + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-server-create.sh ------------------------------------"); + + // Persist to DB + persistApplicationMasterNode(logList, applicationNodeDto, applicationNodeDto.privateKeyBase64(), applicationNodeDto.publicKey(), + wireguardPrivateKey, wireguardPublicKey); + } else { + String wireguardWorkerIp = wireguardNetworkPortion + "2"; + ApplicationMasterNode masterNode = applicationMasterNodeRepository.findByApplicationUUID(applicationNodeDto.applicationUUID()); + if (masterNode != null) { + List workerNodes = applicationWorkerNodeRepository.findWorkerNodesByMasterNode(masterNode); + + logService.log(logList, Level.INFO, ONM, "Worker Nodes " + workerNodes.size()); + + if (!workerNodes.isEmpty()) wireguardWorkerIp = wireguardNetworkPortion + (workerNodes.size() + 2); + var workerNodeClientName = "wg" + wireguardWorkerIp; + + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-create_server.sh ------------------------------------"); + logService.log(logList, Level.INFO, ONM, "SCP FILE wg-client-create_server.sh to HOST: " + masterNode.getPublicIp()); + + remoteCodeExecutionService.scpFile(masterNode.getSshUsername(),masterNode.getPublicIp(), + 22, masterNode.getOpenSSLPrivateKey(), 30L, + wgBootstrapAgentScriptsDir + "/client/wg-client-create_server.sh", + "wireguard",null); + logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-client-create_server.sh to HOST: " + masterNode.getPublicIp()); + var permissionsCommandServer = "sudo chmod +x /home/" + masterNode.getSshUsername() + "/wireguard/wg-client-create_server.sh"; + var executeCommandServer = "sudo /home/" + masterNode.getSshUsername() + "/wireguard/wg-client-create_server.sh " + workerNodeClientName + " " + wireguardPrivateKey + " " + + wireguardPublicKey + " " + masterNode.getSshUsername() + " " + masterNode.getWireguardPublicKey() + " " + masterNode.getPublicIp()+":"+"51820" + " " + + wireguardWorkerIp + " " + wireguardAllowedIps; + remoteCodeExecutionService.runCommand(masterNode.getSshUsername(),masterNode.getOpenSSLPrivateKey(),masterNode.getPublicIp(), + 22,30L, + permissionsCommandServer + ";" + executeCommandServer, null); + logService.log(logList, Level.INFO, ONM, "COMMAND wg-client-create_server.sh for HOST " + masterNode.getPublicIp() + " COMPLETED!"); + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-create_server.sh ------------------------------------"); + + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-create_client.sh ------------------------------------"); + remoteCodeExecutionService.scpFile(applicationNodeDto.sshUsername(),applicationNodeDto.publicIp(), + 22,applicationNodeDto.privateKeyBase64(),30L, + wgBootstrapAgentScriptsDir + "/client/wg-client-create_client.sh", + "wireguard",null); + logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-client-create_client.sh to HOST: " + applicationNodeDto.publicIp()); + var permissionsCommandClient = "sudo chmod +x /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-client-create_client.sh"; + var executeCommandClient = "sudo /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-client-create_client.sh " + applicationNodeDto.sshUsername() + " " + + "\"" + masterNode.getOpenSSLPrivateKey() + "\" " + masterNode.getPublicIp() + " " + workerNodeClientName + " " + masterNode.getSshUsername(); + remoteCodeExecutionService.runCommand(applicationNodeDto.sshUsername(),applicationNodeDto.privateKeyBase64(),applicationNodeDto.publicIp(), + 22,30L, permissionsCommandClient + ";" + executeCommandClient, null); + logService.log(logList, Level.INFO, ONM, "COMMAND wg-client-create_client.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!"); + + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-create_client.sh ------------------------------------"); + + // Persist to DB + persistApplicationWorkerNode(logList, applicationNodeDto, masterNode, wireguardPrivateKey, wireguardPublicKey, wireguardWorkerIp); + } + } + + return logList; + } + + @Transactional + public List evaluateNodeDeletion(ApplicationNodeDto applicationNodeDto) { + var logList = new ArrayList(); + + if(applicationNodeDto.isMaster().equals(Boolean.TRUE)) { + ApplicationMasterNode masterNode = applicationMasterNodeRepository.findByApplicationUUID(applicationNodeDto.applicationUUID()); + if (masterNode == null) { + logService.log(logList, Level.INFO, ONM, "FAILURE -> Could not find an Application Master Node with applicationUUID " + + applicationNodeDto.applicationUUID()); + + return logList; + } + + // Check If Master has workers below him + List workerNodes = applicationWorkerNodeRepository.findWorkerNodesByMasterNode(masterNode); + if(workerNodes.isEmpty()) { + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-server-delete.sh ------------------------------------"); + logService.log(logList, Level.INFO, ONM, "SCP FILE wg-server-delete.sh to HOST: " + applicationNodeDto.publicIp()); + + remoteCodeExecutionService.scpFile(applicationNodeDto.sshUsername(),applicationNodeDto.publicIp(), + 22,applicationNodeDto.privateKeyBase64(),30L, + wgBootstrapAgentScriptsDir + "/server/wg-server-delete.sh", + "wireguard",null); + logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-server-delete.sh to HOST: " + applicationNodeDto.publicIp()); + var permissionsCommand = "sudo chmod +x /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-server-delete.sh"; + var executeCommand = "sudo /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-server-delete.sh " + applicationNodeDto.sshUsername(); + remoteCodeExecutionService.runCommand(applicationNodeDto.sshUsername(),applicationNodeDto.privateKeyBase64(),applicationNodeDto.publicIp(), + 22,30L, + permissionsCommand + ";" + executeCommand, null); + logService.log(logList, Level.INFO, ONM, "COMMAND wg-server-delete.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!"); + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-server-delete.sh ------------------------------------"); + deleteApplicationMasterNode(logList, masterNode); + } else { + logService.log(logList, Level.INFO, ONM, "The Application Master Node with PublicIP " + applicationNodeDto.publicIp() + + " and applicationUUID " + applicationNodeDto.applicationUUID() + " has " + workerNodes.size() + " worker nodes."); + //TODO: What happens when a request for deletion on a WG Server appears and it has workers running?? + } + } else { + var workerNode = applicationWorkerNodeRepository.findWorkerByPublicIp(applicationNodeDto); + if(workerNode == null) { + logService.log(logList, Level.INFO, ONM, "FAILURE -> Could not find an Application Worker Node with applicationUUID " + applicationNodeDto.publicIp()); + return logList; + } + + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-delete_client.sh ------------------------------------"); + logService.log(logList, Level.INFO, ONM, "SCP FILE wg-client-delete_client.sh to HOST: " + applicationNodeDto.publicIp()); + remoteCodeExecutionService.scpFile(applicationNodeDto.sshUsername(),applicationNodeDto.publicIp(), + 22,applicationNodeDto.privateKeyBase64(),30L, + wgBootstrapAgentScriptsDir + "/client/wg-client-delete_client.sh", + "wireguard",null); + logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-client-delete_client_script.sh to HOST: " + applicationNodeDto.publicIp()); + var permissionsCommandClient = "sudo chmod +x /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-client-delete_client.sh"; + var executeCommandClient = "sudo /home/" + applicationNodeDto.sshUsername() + "/wireguard/wg-client-delete_client.sh " + applicationNodeDto.sshUsername() + + " " + "wg" + workerNode.getWireguardIp(); + remoteCodeExecutionService.runCommand(applicationNodeDto.sshUsername(),applicationNodeDto.privateKeyBase64(),applicationNodeDto.publicIp(), + 22,30L, + permissionsCommandClient + ";" + executeCommandClient, null); + logService.log(logList, Level.INFO, ONM, "COMMAND wg-client-delete_client.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!"); + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-delete_client.sh ------------------------------------"); + + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-delete_server.sh ------------------------------------"); + logService.log(logList, Level.INFO, ONM, "SCP FILE wg-client-delete_server.sh to HOST: " + workerNode.getApplicationMasterNode().getPublicIp()); + remoteCodeExecutionService.scpFile(workerNode.getApplicationMasterNode().getSshUsername(),workerNode.getApplicationMasterNode().getPublicIp(), + 22,workerNode.getApplicationMasterNode().getOpenSSLPrivateKey(),30L, + wgBootstrapAgentScriptsDir + "/client/wg-client-delete_server.sh", + "wireguard",null); + logService.log(logList, Level.INFO, ONM, "SCP COMPLETED! Ready to run wg-client-delete_server.sh to HOST: " + workerNode.getApplicationMasterNode().getPublicIp()); + var permissionsCommandServer = "sudo chmod +x /home/" + workerNode.getApplicationMasterNode().getSshUsername() + "/wireguard/wg-client-delete_server.sh"; + var executeCommandServer = "sudo /home/" + workerNode.getApplicationMasterNode().getSshUsername() + "/wireguard/wg-client-delete_server.sh " + "wg" + workerNode.getWireguardIp() + + " " + workerNode.getWireguardPublicKey() + " " + applicationNodeDto.sshUsername(); + remoteCodeExecutionService.runCommand(workerNode.getApplicationMasterNode().getSshUsername(),workerNode.getApplicationMasterNode().getOpenSSLPrivateKey(), + workerNode.getApplicationMasterNode().getPublicIp(),22,30L, permissionsCommandServer + ";" + executeCommandServer, null); + logService.log(logList, Level.INFO, ONM, "COMMAND wg-client-delete_server.sh for HOST " + applicationNodeDto.publicIp() + " COMPLETED!"); + logService.log(logList, Level.INFO, ONM, "------------------------------------ wg-client-delete_server.sh ------------------------------------"); + + deleteApplicationWorkerNode(logList, workerNode); + } + + return logList; + } + + private void deleteApplicationMasterNode(List logList, ApplicationMasterNode masterNode) { + try { + applicationMasterNodeRepository.delete(masterNode); + logService.log(logList, Level.INFO, ONM, "SUCCESS -> Application Node Master (" + masterNode.getPublicIp() + ", " + + masterNode.getApplicationUUID() + ") successfully deleted from the DB!"); + } catch (Exception e) { + logService.log(logList, Level.WARNING, ONM, "FAILURE -> The Application Node Master (" + masterNode.getPublicIp() + ", " + + masterNode.getApplicationUUID() + ") failed to be deleted from the DB!"); + } + } + + private void deleteApplicationWorkerNode(List logList, ApplicationWorkerNode workerNode) { + try { + applicationWorkerNodeRepository.delete(workerNode); + logService.log(logList, Level.INFO, ONM, "SUCCESS -> Application Node Worker (" + workerNode.getPublicIp() + ", " + + workerNode.getApplicationMasterNode().getApplicationUUID() + ") successfully deleted from the DB!"); + } catch (Exception e) { + logService.log(logList, Level.WARNING, ONM, "FAILURE -> The Application Node Worker (" + workerNode.getPublicIp() + ", " + + workerNode.getApplicationMasterNode().getApplicationUUID() + ") failed to be deleted from the DB!"); + } + } +} diff --git a/network-manager/src/main/java/eu/nebulous/service/LogService.java b/network-manager/src/main/java/eu/nebulous/service/LogService.java new file mode 100644 index 0000000..f69c872 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/service/LogService.java @@ -0,0 +1,24 @@ +package eu.nebulous.service; + +import eu.nebulous.dto.LogDto; +import jakarta.enterprise.context.ApplicationScoped; + +import java.util.Date; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +@ApplicationScoped +public class LogService { + private static final Logger logger = Logger.getLogger(LogService.class.getName()); + + public void log(List logList, Level logLevel, String title, String message) { + var date = new Date(); + + // Add log events to logList + logList.add(new LogDto(date, logLevel, title, message)); + + // Log events + logger.log(logLevel, "{0}: {1}", new Object[]{date, message}); + } +} diff --git a/network-manager/src/main/java/eu/nebulous/service/RemoteCodeExecutionService.java b/network-manager/src/main/java/eu/nebulous/service/RemoteCodeExecutionService.java new file mode 100644 index 0000000..ce4c778 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/service/RemoteCodeExecutionService.java @@ -0,0 +1,135 @@ +package eu.nebulous.service; + +import jakarta.enterprise.context.ApplicationScoped; +import org.apache.sshd.client.SshClient; +import org.apache.sshd.client.channel.ClientChannelEvent; +import org.apache.sshd.common.keyprovider.FileKeyPairProvider; +import org.apache.sshd.scp.client.ScpClientCreator; + +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Base64; +import java.util.Collections; +import java.util.Date; +import java.util.EnumSet; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +@ApplicationScoped +public class RemoteCodeExecutionService { + + private static final Logger logger = Logger.getLogger(RemoteCodeExecutionService.class.getName()); + + public void runCommand(String username, String privateKeyBase64, String host, int port, + long defaultTimeoutSeconds, String command, String password) { + + File privateKeyFile = createTmpFile(privateKeyBase64); + + var client = SshClient.setUpDefaultClient(); + client.start(); + + try (var session = client.connect(username, host, port) + .verify(defaultTimeoutSeconds, TimeUnit.SECONDS).getSession()) { + + if (password != null) { + session.addPasswordIdentity(password); + } else { + var fileKeyPairProvider = new FileKeyPairProvider(); + fileKeyPairProvider.setPaths(Collections.singleton(Paths.get(privateKeyFile.getAbsolutePath()))); + var key = fileKeyPairProvider.loadKeys(null).iterator().next(); + + session.addPublicKeyIdentity(key); + } + + session.auth().verify(defaultTimeoutSeconds, TimeUnit.SECONDS); // Timeout + + try (var responseStream = new ByteArrayOutputStream(); + var channel = session.createExecChannel(command)) { + channel.setOut(responseStream); + + try { + channel.open().verify(defaultTimeoutSeconds, TimeUnit.SECONDS); + try (var pipedIn = channel.getInvertedIn()) { + pipedIn.write(command.getBytes()); + pipedIn.flush(); + } + + channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), + TimeUnit.SECONDS.toMillis(defaultTimeoutSeconds)); + var responseString = responseStream.toString(); + + logger.log(Level.INFO, "Response: {0}", new Object[]{responseString}); + } finally { + channel.close(false); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + client.stop(); + privateKeyFile.delete(); + } + } + + public void scpFile(String username, String host, int port, String privateKeyBase64, long defaultTimeoutSeconds, + String localFilePath, String remoteTargetFolder, String password) { + + File privateKeyFile = createTmpFile(privateKeyBase64); + + var client = SshClient.setUpDefaultClient(); + client.start(); + + try (var session = client.connect(username, host, port) + .verify(defaultTimeoutSeconds, TimeUnit.SECONDS).getSession()) { + + if (password != null) { + session.addPasswordIdentity(password); + } else { + var fileKeyPairProvider = new FileKeyPairProvider(); + fileKeyPairProvider.setPaths(Collections.singleton(Paths.get(privateKeyFile.getAbsolutePath()))); + var key = fileKeyPairProvider.loadKeys(null).iterator().next(); + + session.addPublicKeyIdentity(key); + } + + session.auth().verify(defaultTimeoutSeconds, TimeUnit.SECONDS); + + var creator = ScpClientCreator.instance(); + var scpClient = creator.createScpClient(session); + + // To SCP a file to the remote system + scpClient.upload(localFilePath, "/home/" + username + "/" + remoteTargetFolder); + } catch (IOException e) { + e.printStackTrace(); + } finally { + client.stop(); + privateKeyFile.delete(); + } + } + + private File createTmpFile(String privateKey) { + try { + // Create temp file. + var temp = File.createTempFile("originPK" + UUID.randomUUID(), ".txt"); + + // Write to temp file + var out = new BufferedWriter(new FileWriter(temp)); + var decodedString = new String(Base64.getMimeDecoder().decode(privateKey.getBytes()), StandardCharsets.UTF_8); + + out.write(decodedString); + out.close(); + + return temp; + } catch (IOException e) { + logger.log(Level.SEVERE, "{0} -> Problem creating tmp file for Origin Private Key File", new Object[]{new Date()}); + return null; + } + } +} diff --git a/network-manager/src/main/java/eu/nebulous/service/SSHKeyPairGeneratorService.java b/network-manager/src/main/java/eu/nebulous/service/SSHKeyPairGeneratorService.java new file mode 100644 index 0000000..b3aa867 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/service/SSHKeyPairGeneratorService.java @@ -0,0 +1,82 @@ +package eu.nebulous.service; + +import jakarta.enterprise.context.ApplicationScoped; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.jcajce.JcaPEMWriter; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.security.Key; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.Security; +import java.security.interfaces.RSAPublicKey; +import java.util.Base64; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +@ApplicationScoped +public class SSHKeyPairGeneratorService { + + private static final Logger logger = Logger.getLogger(SSHKeyPairGeneratorService.class.getName()); + + public Map createOpenSSL(String publicIp) { + var openSSLKeyPairHashMap = new HashMap(); + try { + Security.addProvider(new BouncyCastleProvider()); + + // Generate the RSA Key Pair + var keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + var pair = keyGen.generateKeyPair(); + + var privateKeyString = convertKeyToString(pair.getPrivate()); + var privateKeyBase64String = Base64.getEncoder().encodeToString(privateKeyString.getBytes()); + + openSSLKeyPairHashMap.put("private", privateKeyBase64String); + // Output private key + logger.log(Level.INFO, "{0}: SUCCESS -> OpenSSL Private Key Base64 for {1} just created: {2}", + new Object[]{new Date(), publicIp, privateKeyBase64String}); + + // Convert public key to SSH format + var sshPublicKey = convertPublicKeyToSSHFormat(pair.getPublic()); + openSSLKeyPairHashMap.put("public", sshPublicKey + " wg-public-key"); + + logger.log(Level.INFO, "{0}: SUCCESS -> OpenSSL Public Key (SSH Format) for {1} just created: {2} wg-public-key", + new Object[]{new Date(), publicIp, sshPublicKey}); + + } catch (Exception e) { + logger.log(Level.WARNING, "{0}: FAILURE -> Error generating OpenSSL Key Pair for {1}", + new Object[]{new Date(), publicIp}); + } + + return openSSLKeyPairHashMap; + } + + private static String convertKeyToString(Key key) throws IOException { + var writer = new StringWriter(); + try (var pemWriter = new JcaPEMWriter(writer)) { + pemWriter.writeObject(key); + } + return writer.toString(); + } + + private static String convertPublicKeyToSSHFormat(PublicKey publicKey) throws IOException { + var rsaPublicKey = (RSAPublicKey) publicKey; + var byteOs = new ByteArrayOutputStream(); + var dos = new DataOutputStream(byteOs); + dos.writeInt("ssh-rsa".getBytes().length); + dos.write("ssh-rsa".getBytes()); + dos.writeInt(rsaPublicKey.getPublicExponent().toByteArray().length); + dos.write(rsaPublicKey.getPublicExponent().toByteArray()); + dos.writeInt(rsaPublicKey.getModulus().toByteArray().length); + dos.write(rsaPublicKey.getModulus().toByteArray()); + var publicKeyEncoded = new String(Base64.getEncoder().encode(byteOs.toByteArray())); + return "ssh-rsa " + publicKeyEncoded; + } +} diff --git a/network-manager/src/main/java/eu/nebulous/service/WGKeyPairGeneratorService.java b/network-manager/src/main/java/eu/nebulous/service/WGKeyPairGeneratorService.java new file mode 100644 index 0000000..cfe5926 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/service/WGKeyPairGeneratorService.java @@ -0,0 +1,50 @@ +package eu.nebulous.service; + +import jakarta.enterprise.context.ApplicationScoped; +import org.bouncycastle.crypto.generators.X25519KeyPairGenerator; +import org.bouncycastle.crypto.params.X25519KeyGenerationParameters; +import org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +import org.bouncycastle.crypto.params.X25519PublicKeyParameters; +import org.bouncycastle.util.encoders.Base64; + +import java.security.SecureRandom; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +@ApplicationScoped +public class WGKeyPairGeneratorService { + + private static final Logger logger = Logger.getLogger(WGKeyPairGeneratorService.class.getName()); + + public Map createWireguardKeyPair(String publicIp) { + var wireguardKeyPairHashMap = new HashMap(); + // Initialize key generator + var keyPairGenerator = new X25519KeyPairGenerator(); + keyPairGenerator.init(new X25519KeyGenerationParameters(new SecureRandom())); + + // Generate key pair + var keyPair = keyPairGenerator.generateKeyPair(); + + // Extract private and public keys + var privateKey = (X25519PrivateKeyParameters) keyPair.getPrivate(); + var publicKey = (X25519PublicKeyParameters) keyPair.getPublic(); + + // Encode keys to Base64 + var privateKeyBase64 = Base64.toBase64String(privateKey.getEncoded()); + var publicKeyBase64 = Base64.toBase64String(publicKey.getEncoded()); + + wireguardKeyPairHashMap.put("private", privateKeyBase64); + wireguardKeyPairHashMap.put("public", publicKeyBase64); + + // Output the keys + logger.log(Level.INFO, "{0}: SUCCESS -> Private Key for {1} just created: {2}", + new Object[]{new Date(), publicIp, privateKeyBase64}); + logger.log(Level.INFO, "{0}: SUCCESS -> Public Key for {1} just created: {2}", + new Object[]{new Date(), publicIp, publicKeyBase64}); + + return wireguardKeyPairHashMap; + } +} diff --git a/network-manager/src/main/java/eu/nebulous/util/Util.java b/network-manager/src/main/java/eu/nebulous/util/Util.java new file mode 100644 index 0000000..b237d61 --- /dev/null +++ b/network-manager/src/main/java/eu/nebulous/util/Util.java @@ -0,0 +1,26 @@ +package eu.nebulous.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.nebulous.exception.NotFoundAlertException; +import jakarta.enterprise.context.ApplicationScoped; + +import java.io.PrintWriter; +import java.io.StringWriter; + +@ApplicationScoped +public class Util { + public String exceptionResponse(Exception e){ + var errors = new StringWriter(); + e.printStackTrace(new PrintWriter(errors)); + return errors.toString(); + } + + public String toString(Object obj) { + try { + return new ObjectMapper().writeValueAsString(obj); + } catch (JsonProcessingException e) { + throw new NotFoundAlertException(e.toString()); + } + } +} \ No newline at end of file diff --git a/network-manager/src/main/resources/application.yml b/network-manager/src/main/resources/application.yml new file mode 100644 index 0000000..0cc299b --- /dev/null +++ b/network-manager/src/main/resources/application.yml @@ -0,0 +1,39 @@ +mp: + openapi: + extensions: + smallrye: + info: + title: 'API Specification' + version: '1.0' + description: 'Exposed REST Services in order to talk with the world' + name: 'NebulOus Overlay Network Manager' + +quarkus: + datasource: + db-kind: postgresql + jdbc: + url: ${POSTGRES_CONNECTION_STRING} + username: ${POSTGRES_USER} + password: ${POSTGRES_PASSWORD} + + hibernate-orm: + database: + generation: update + + smallrye-openapi: + path: '/api/openapi' + security-scheme: 'jwt' + security-scheme-name: 'Swagger Authentication' + security-scheme-description: 'User Authentication through Keycloak' + + swagger-ui: + title: 'API Documentation' + theme: material + footer: © 2024 + always-include: true + path: '/api/swagger' + +"%prod": + quarkus: + package: + type: uber-jar diff --git a/network-manager/wg-bootstrap-agent-scripts/client/README.md b/network-manager/wg-bootstrap-agent-scripts/client/README.md new file mode 100644 index 0000000..37bb078 --- /dev/null +++ b/network-manager/wg-bootstrap-agent-scripts/client/README.md @@ -0,0 +1,7 @@ +# Create Client + +* Server Name: wg0 +* Client Name: $CLIENT_NAME +* Wireguard Client Directory: /etc/wireguard/clients/$CLIENT_NAME +* Client Conf: /etc/wireguard/clients/$CLIENT_NAME/$CLIENT_NAME.conf +* Server Conf: /etc/wireguard/wg0.conf diff --git a/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_client.sh b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_client.sh new file mode 100644 index 0000000..0f3a3f8 --- /dev/null +++ b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_client.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Check if sufficient arguments are provided +if [ "$#" -ne 5 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Script parameter +WORKER_SSH_USERNAME="$1" +OPENSSL_PRIVATE_KEY="$2" +SERVER_IP="$3" +CLIENT_NAME="$4" +MASTER_SSH_USERNAME="$5" + +# Update Package Repository. Upgrade and Autoremove Packages +sudo DEBIAN_FRONTEND=noninteractive apt-get -y update +sudo DEBIAN_FRONTEND=noninteractive apt-get -y upgrade +sudo DEBIAN_FRONTEND=noninteractive apt-get -y autoremove + + +# Step 1: Install WireGuard +if ! command -v wg > /dev/null; then + sudo DEBIAN_FRONTEND=noninteractive apt install -y wireguard + sudo DEBIAN_FRONTEND=noninteractive apt install -y resolvconf +fi + +# Step 2: Base64 Decode the OpenSSH Private Key file +echo $OPENSSL_PRIVATE_KEY | base64 -d --ignore-garbage > /home/$WORKER_SSH_USERNAME/wg-private-key.key +chmod 400 /home/$WORKER_SSH_USERNAME/wg-private-key.key + +# Step 3: Secure Copy to WG Server to get your conf file +scp -o StrictHostKeyChecking=no -i /home/$WORKER_SSH_USERNAME/wg-private-key.key $MASTER_SSH_USERNAME@$SERVER_IP:/home/$MASTER_SSH_USERNAME/wireguard/clients/$CLIENT_NAME/$CLIENT_NAME.conf /home/$WORKER_SSH_USERNAME/wireguard +sudo cp /home/$WORKER_SSH_USERNAME/wireguard/$CLIENT_NAME.conf /etc/wireguard/$CLIENT_NAME.conf + +# Step 4: Enable and Start WireGuard Client Interface +sudo systemctl enable wg-quick@$CLIENT_NAME +sudo systemctl start wg-quick@$CLIENT_NAME + +echo "WireGuard client configured and started for $CLIENT_NAME" diff --git a/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_server.sh b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_server.sh new file mode 100644 index 0000000..1d34081 --- /dev/null +++ b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-create_server.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# Check if sufficient arguments are provided +if [ "$#" -ne 8 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Script parameters +SERVER_NAME="wg0" +CLIENT_NAME="$1" +WG_CLIENT_PRIVATE_KEY="$2" +WG_CLIENT_PUBLIC_KEY="$3" +SSH_USERNAME="$4" +SERVER_PUBLIC_KEY="$5" +SERVER_IP_PORT="$6" +CLIENT_VPN_IP="$7" +ALLOWED_IPS="$8" +WG_DIR="/etc/wireguard/clients/$CLIENT_NAME" +CLIENT_CONF="$WG_DIR/${CLIENT_NAME}.conf" +SERVER_CONF="/etc/wireguard/${SERVER_NAME}.conf" + +# Step 1: Install WireGuard (if not already installed) +if ! command -v wg > /dev/null; then + sudo DEBIAN_FRONTEND=noninteractive apt install -y wireguard +fi + +# Step 2: Create client directory +sudo mkdir -p "$WG_DIR" +mkdir -p /home/$SSH_USERNAME/wireguard/clients/$CLIENT_NAME + +# Step 3: Generate Client Keys +sudo echo $WG_CLIENT_PRIVATE_KEY > "$WG_DIR/${CLIENT_NAME}_privatekey" +sudo echo $WG_CLIENT_PUBLIC_KEY > "$WG_DIR/${CLIENT_NAME}_publickey" +client_private_key=$(sudo cat "$WG_DIR/${CLIENT_NAME}_privatekey") +client_public_key=$(sudo cat "$WG_DIR/${CLIENT_NAME}_publickey") + +# Step 4: Configure WireGuard Client +sudo bash -c "cat > $CLIENT_CONF <> $SERVER_CONF" + +# Step 6: Restart WireGuard to apply changes +sudo systemctl restart wg-quick@${SERVER_NAME} + +echo "Client configuration for $CLIENT_NAME created and added to server config." +echo "Transfer the client configuration to your client machine. Example command:" +echo "scp $CLIENT_CONF user@client-ip:/path/to/destination" diff --git a/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_client.sh b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_client.sh new file mode 100644 index 0000000..346944d --- /dev/null +++ b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_client.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Check if sufficient arguments are provided +if [ "$#" -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Script parameter +SSH_USERNAME="$1" +WG_INTERFACE_NAME="$2" + +# Step 1: Stop and Disable WireGuard Interface +sudo systemctl stop wg-quick@$WG_INTERFACE_NAME +sudo systemctl disable wg-quick@$WG_INTERFACE_NAME + +# Step 2: Remove Wireguard packages +sudo apt-get remove --purge -y wireguard +sudo apt-get autoremove -y + +echo "Wireguard packages have been removed." + +# Step 3: Remove Wireguard related directories +sudo rm -rf /etc/wireguard +sudo rm -rf /home/$SSH_USERNAME/wireguard + +echo "WireGuard configuration files removed." + +# Step 4: Remove WG OpenSSL Private Key +sudo rm -rf /home/$SSH_USERNAME/wg-private-key.key + +# Step 5: Remove OpenSSL Public Key +sed -i '/wireguard-pub/d' /home/$SSH_USERNAME/.ssh/authorized_keys + +echo "WireGuard client $WG_INTERFACE_NAME has been stopped and disabled." diff --git a/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_server.sh b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_server.sh new file mode 100644 index 0000000..82edaa8 --- /dev/null +++ b/network-manager/wg-bootstrap-agent-scripts/client/wg-client-delete_server.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Check if the client public key is provided +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Script parameter +SERVER_NAME="wg0" +CLIENT_NAME="$1" +CLIENT_PUBLIC_KEY="$2" +SSH_USERNAME="$3" + +# Step 1: Remove the client configuration from the server +sudo wg set ${SERVER_NAME} peer ${CLIENT_PUBLIC_KEY} remove + +# Step 2: Remove the client config file +sudo rm -rf /etc/wireguard/clients/${CLIENT_NAME} +sudo rm -rf /home/$SSH_USERNAME/wireguard/clients/${CLIENT_NAME} + +# Step 3: Restart WireGuard to apply changes +sudo systemctl restart wg-quick@${SERVER_NAME} + +echo "Client with public key $CLIENT_PUBLIC_KEY has been removed from the server configuration." diff --git a/network-manager/wg-bootstrap-agent-scripts/nm-bootstrap-script.sh b/network-manager/wg-bootstrap-agent-scripts/nm-bootstrap-script.sh new file mode 100755 index 0000000..fb3ffea --- /dev/null +++ b/network-manager/wg-bootstrap-agent-scripts/nm-bootstrap-script.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# "CREATE" or "DELETE" Overlay Node +ACTION=$1 +# Define Application Node Type ("MASTER","WORKER") +NODE_TYPE=$2 +# Application UUID +APPLICATION_UUID=$3 +# Overlay Network Manager Public IP +ONM_IP=$4 + +# Get the public IP +public_ip=$(curl -s http://httpbin.org/ip | grep -oP '(?<="origin": ")[^"]*') + +# Get the Application UUID from the environment variable +application_uuid=$APPLICATION_UUID + +# Get the currently logged in user (assuming single user login) +logged_in_user=$(whoami) + +# Get the isMaster variable from the environment variable +if [ "$NODE_TYPE" == "MASTER" ]; then + IS_MASTER="true"; +elif [ "$NODE_TYPE" == "WORKER" ]; then + IS_MASTER="false" +fi + +# Check if string1 is equal to string2 +if [ "$ACTION" == "CREATE" ]; then + echo "Creating OpenSSH Public/Private Key Pair..." + # Create Wireguard Folder to accept the wireguard scripts + mkdir -p /home/${logged_in_user}/wireguard + + # Create OpenSSH Public/Private Key files + ssh-keygen -C wireguard-pub -t rsa -b 4096 -f /home/${logged_in_user}/wireguard/wireguard -N "" + + cat /home/${logged_in_user}/wireguard/wireguard.pub >> /home/${logged_in_user}/.ssh/authorized_keys +fi + +PRIVATE_KEY_FILE=$(cat /home/${logged_in_user}/wireguard/wireguard | base64 | tr '\n' ' ') + +PAYLOAD=$(cat < " + exit 1 +fi + +# Script parameters +WG_SERVER_PRIVATE_KEY="$1" +WG_SERVER_PUBLIC_KEY="$2" +WG_INTERFACE="wg0" +SERVER_IP="$3" +LISTEN_PORT="51820" +WG_DIR="/etc/wireguard" +SERVER_KEYS_DIR="$WG_DIR/server_keys" +SERVER_CONF="$WG_DIR/$WG_INTERFACE.conf" + +# Update Package Repository. Upgrade and Autoremove Packages +sudo DEBIAN_FRONTEND=noninteractive apt-get -y update +sudo DEBIAN_FRONTEND=noninteractive apt-get -y upgrade +sudo DEBIAN_FRONTEND=noninteractive apt-get -y autoremove + +# Step 1: Install WireGuard package +if ! command -v wg > /dev/null; then + sudo DEBIAN_FRONTEND=noninteractive apt install -y wireguard + sudo DEBIAN_FRONTEND=noninteractive apt install -y resolvconf +fi + +# Step 2: Create directories for keys and configuration +sudo mkdir -p "$SERVER_KEYS_DIR" +sudo mkdir -p "$WG_DIR" + +# Step 3: Generate Server Keys +sudo echo $WG_SERVER_PRIVATE_KEY > "$SERVER_KEYS_DIR/${WG_INTERFACE}_privatekey" +sudo echo $WG_SERVER_PUBLIC_KEY > "$SERVER_KEYS_DIR/${WG_INTERFACE}_publickey" +server_private_key=$(sudo cat "$SERVER_KEYS_DIR/${WG_INTERFACE}_privatekey") + +# Step 4: Create Server Configuration File +sudo bash -c "cat > $SERVER_CONF <