diff --git a/README.md b/README.md index dcea9fd..0a5fe32 100644 --- a/README.md +++ b/README.md @@ -1,112 +1,51 @@ -See https://docs.google.com/document/d/15yod6K_ZbNkJ_ern7gwpxjBkdJIlHXORfYZ3CGQhnEM/edit?usp=sharing for a full version with images +# code-with-quarkus -# Introduction -Currently we rely on CPaaS to submit requests to PSSaaS which then invokes the PSSC scanning container. The idea behind the ScanChain api is to act as an interaction point for services to be able to directly access our scan tooling. +This project uses Quarkus, the Supersonic Subatomic Java Framework. -Our api will be written in Quarkus for ease of use and deployment to OpenShift, we will also use Tekton to assist with CI/CD. +If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ . -# How to build +## Running the application in dev mode -To set up the environment. After cloning the repository: - -``` -cd / -quarkus create app quarkus:dev -mvn -N io.takari:maven:wrapper -``` - -Also, it is necessary to create a local PostgreSQL instance. For development purposes, the parameters are: -``` -username = postgresql -password = password -``` - -ToDo: Create Database Model - - - -To run the Quarkus build in dev mode simply run: -```` +You can run your application in dev mode that enables live coding using: +```shell script ./mvnw compile quarkus:dev -```` -All end points should be avaliable on localhost:8080/{endpoint}. The endpoints are listed in the endpoints section - - - -# Deploying to OpenShift (https://quarkus.io/guides/deploying-to-openshift) -Part of the advantage of working with quarkus is the ease of which we can deploy it to OpenShift. We have the OpenShift extension already installed via the pom, - -All that should be required to build and deploy OpenShift is to login to OpenShift via the usual method (oc login (creds) for example). Before running a build command: - -You can then expose the routes (oc expose {route}), then your application should be accessible on the OpenShift cluster. This is verifiable either by using the console to request which services are running (oc get svc) or by using the web console which should display the service graphically. - -# Design diagram -API endpoint diagram with all endpoints DB links, connections to further services (PNC API etc) - -# API endpoints - -## /{scanId} - GET request for retrieving scans -This is a simple request for retrieving scans that are stored in our postgresql database. The assigned scanId will return the whole scan payload in JSON format. - -## / - POST request takes a JSON payload to start scans (Maybe isnt relevant/shouldnt be included in the future) - -Creating scans via passing fully formed JSON payloads. The standard JSON format should contain: -product-id -event-id -is-managed-service -component-list -See appendix 1 for a provided example - -## /scanRequest - Post request for starting scans - -There are several different types of build that should be retrieved from the backend source. Different inputs are required based off the build source. - -The required fields for BREW builds are: -buildSystemType -brewId -brewNVR - matches brewId -pncId -artifactType -fileName -builtFromSource - -The required fields for git builds are: -buildSystemType -repository -reference -commitId - -The required fields for PNC builds are: -buildSystemType -buildId +``` -This information should allow us to have all the requirements for retrieving and then starting a scan when requested from the required sources. +> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/. -## /startScan - PUT request to start off the relevant scan +## Packaging and running the application -Only requires the scanId and should start off the relevant scan, should return a success only on finished or failure if there's no further response after timeout. -## /removeScan - DELETE request to remove a scan build from DB +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 an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory. -Only requires the scanId should remove the relevant scan from our DB. Should return a success or failure. +The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`. -# Expanded work to do +If you want to build an _über-jar_, execute the following command: +```shell script +./mvnw package -Dquarkus.package.type=uber-jar +``` -## Jenkins +The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`. -Haven't looked into the correct way for the API to interact with Jenkins needs more investigation. +## Creating a native executable -## Jira tickets still to do: -https://issues.redhat.com/browse/PSSECMGT-1548 -https://issues.redhat.com/browse/PSSECMGT-1549 -https://issues.redhat.com/browse/PSSECMGT-1550 -https://issues.redhat.com/browse/PSSECMGT-1551 -https://issues.redhat.com/browse/PSSECMGT-1552 -https://issues.redhat.com/browse/PSSECMGT-1553 -https://issues.redhat.com/browse/PSSECMGT-1554 +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 +``` -# Appendix +You can then execute your native executable with: `./target/code-with-quarkus-1.0.0-SNAPSHOT-runner` -Appendix 1 +If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling. +## Related Guides diff --git a/k8s/linux-krb5.conf b/k8s/linux-krb5.conf new file mode 100644 index 0000000..701d438 --- /dev/null +++ b/k8s/linux-krb5.conf @@ -0,0 +1,36 @@ +includedir /etc/krb5.conf.d/ + +# depending on your config, you may wish to uncomment the following: +# includedir /var/lib/sss/pubconf/krb5.include.d/ + +[libdefaults] + default_realm = IPA.REDHAT.COM + dns_lookup_realm = true + dns_lookup_kdc = true + rdns = false + dns_canonicalize_hostname = false + ticket_lifetime = 24h + forwardable = true + udp_preference_limit = 1 + default_ccache_name = KEYRING:persistent:%{uid} + max_retries = 1 + kdc_timeout = 1500 + +[realms] + + REDHAT.COM = { + default_domain = redhat.com + dns_lookup_kdc = true + master_kdc = kerberos.corp.redhat.com + admin_server = kerberos.corp.redhat.com + } + + IPA.REDHAT.COM = { + default_domain = ipa.redhat.com + dns_lookup_kdc = true + # Trust tickets issued by legacy realm on this host + auth_to_local = RULE:[1:$1@$0](.*@REDHAT\.COM)s/@.*// + auth_to_local = DEFAULT + } +#DO NOT ADD A [domain_realms] section +#https://mojo.redhat.com/docs/DOC-1166841 diff --git a/k8s/stage/edgeroute.yml b/k8s/stage/edgeroute.yml new file mode 100644 index 0000000..735c1a0 --- /dev/null +++ b/k8s/stage/edgeroute.yml @@ -0,0 +1,21 @@ +#oc create route edge --service=osh --dry-run=client -o yaml > edgeroute.yml +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/name: osh + app.kubernetes.io/version: 1.0.0-SNAPSHOT + app.openshift.io/runtime: quarkus + env: stage + name: osh +spec: + port: + targetPort: http + tls: + termination: edge + to: + kind: "" + name: osh + weight: null +status: {} diff --git a/k8s/stage/kerberos-config.yaml b/k8s/stage/kerberos-config.yaml new file mode 100644 index 0000000..786f28c --- /dev/null +++ b/k8s/stage/kerberos-config.yaml @@ -0,0 +1,44 @@ +#oc create configmap kerberos-config --from-file=linux-krb5.conf --dry-run=client -o yaml > kerberos-config.yaml +apiVersion: v1 +data: + linux-krb5.conf: | + includedir /etc/krb5.conf.d/ + + # depending on your config, you may wish to uncomment the following: + # includedir /var/lib/sss/pubconf/krb5.include.d/ + + [libdefaults] + default_realm = IPA.REDHAT.COM + dns_lookup_realm = true + dns_lookup_kdc = true + rdns = false + dns_canonicalize_hostname = false + ticket_lifetime = 24h + forwardable = true + udp_preference_limit = 1 + default_ccache_name = KEYRING:persistent:%{uid} + max_retries = 1 + kdc_timeout = 1500 + + [realms] + + REDHAT.COM = { + default_domain = redhat.com + dns_lookup_kdc = true + master_kdc = kerberos.corp.redhat.com + admin_server = kerberos.corp.redhat.com + } + + IPA.REDHAT.COM = { + default_domain = ipa.redhat.com + dns_lookup_kdc = true + # Trust tickets issued by legacy realm on this host + auth_to_local = RULE:[1:$1@$0](.*@REDHAT\.COM)s/@.*// + auth_to_local = DEFAULT + } + #DO NOT ADD A [domain_realms] section + #https://mojo.redhat.com/docs/DOC-1166841 +kind: ConfigMap +metadata: + creationTimestamp: null + name: kerberos-config diff --git a/pom.xml b/pom.xml index 77233b1..f3959e6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,9 +1,16 @@ + + + jboss + JBoss repository + http://repository.jboss.org/maven2 + + 4.0.0 - com.redhat.ncaughey - rest-json-quickstart + com.redhat.pctOshWrapper + osh 1.0.0-SNAPSHOT 3.10.1 @@ -28,6 +35,11 @@ + + io.quarkiverse.kerberos + quarkus-kerberos + 1.0.0 + io.quarkus quarkus-openshift @@ -37,11 +49,14 @@ json 20220320 + org.postgresql postgresql 42.6.0 + + org.hibernate hibernate-core @@ -50,10 +65,12 @@ org.glassfish.jaxb jaxb-runtime + io.quarkus quarkus-jdbc-postgresql + io.quarkus quarkus-resteasy-reactive-jackson @@ -77,16 +94,21 @@ 1.18.26 provided + + javax.validation validation-api 1.0.0.GA + jakarta.persistence jakarta.persistence-api 3.1.0 + + org.eclipse.microprofile.rest.client microprofile-rest-client-api @@ -155,6 +177,19 @@ + + io.smallrye + jandex-maven-plugin + 3.1.1 + + + make-index + + jandex + + + + diff --git a/src/main/docker/Dockerfile.jvm b/src/main/docker/Dockerfile.jvm index 839c411..5ba77be 100644 --- a/src/main/docker/Dockerfile.jvm +++ b/src/main/docker/Dockerfile.jvm @@ -86,6 +86,7 @@ COPY --chown=185 target/quarkus-app/*.jar /deployments/ COPY --chown=185 target/quarkus-app/app/ /deployments/app/ COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ + EXPOSE 8080 USER 185 ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" diff --git a/src/main/java/dto/BrewObj.java b/src/main/java/dto/BrewObj.java index f711502..0497751 100644 --- a/src/main/java/dto/BrewObj.java +++ b/src/main/java/dto/BrewObj.java @@ -5,6 +5,7 @@ import lombok.Builder; import lombok.Getter; import lombok.ToString; import lombok.extern.jackson.Jacksonized; + import java.io.Serializable; @AllArgsConstructor diff --git a/src/main/java/dto/ConnectDB.java b/src/main/java/dto/ConnectDB.java index 37f977d..1944770 100644 --- a/src/main/java/dto/ConnectDB.java +++ b/src/main/java/dto/ConnectDB.java @@ -6,9 +6,7 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; -import static constants.PSGQL.user; -import static constants.PSGQL.password; -import static constants.PSGQL.url; +import static constants.PSGQL.*; // @TODO Replace hard-coded credentials; make use of our secure db connection practice diff --git a/src/main/java/dto/ScanObj.java b/src/main/java/dto/ScanObj.java index 8cf61f2..fe0821e 100644 --- a/src/main/java/dto/ScanObj.java +++ b/src/main/java/dto/ScanObj.java @@ -7,8 +7,7 @@ import lombok.ToString; import lombok.extern.jackson.Jacksonized; import java.io.Serializable; -//still need to fix all the scan objects to be significantly less poorly written -//TODO add interface for the scan objects (is probably the cleanest solution) +import java.io.Serializable; @AllArgsConstructor @Builder diff --git a/src/main/java/rest/CreateGetResource.java b/src/main/java/rest/CreateGetResource.java index 17f33de..67d9bea 100644 --- a/src/main/java/rest/CreateGetResource.java +++ b/src/main/java/rest/CreateGetResource.java @@ -19,6 +19,7 @@ import java.sql.SQLException; // @Path("/api/v1/[osh-scan]") @Path("/scanGet") +@Authenticated public class CreateGetResource { private static final Logger logger = LoggerFactory.getLogger(CreateGetResource.class); diff --git a/src/main/java/rest/CreateScanRequest.java b/src/main/java/rest/CreateScanRequest.java index 7e47d8c..85327c2 100644 --- a/src/main/java/rest/CreateScanRequest.java +++ b/src/main/java/rest/CreateScanRequest.java @@ -22,6 +22,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +@Authenticated @Path("/scanRequest") public class CreateScanRequest { diff --git a/src/main/java/rest/CreateScanResource.java b/src/main/java/rest/CreateScanResource.java index 1ca03ce..35564d7 100644 --- a/src/main/java/rest/CreateScanResource.java +++ b/src/main/java/rest/CreateScanResource.java @@ -3,6 +3,9 @@ package rest; import dto.ConnectDB; import dto.ScanObjPayload; import dto.ScanObj; +import dto.ScanObjPayload; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.json.JSONObject; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.json.JSONException; diff --git a/src/main/java/rest/CreateStartScan.java b/src/main/java/rest/CreateStartScan.java index 0aade1d..5461722 100644 --- a/src/main/java/rest/CreateStartScan.java +++ b/src/main/java/rest/CreateStartScan.java @@ -2,6 +2,8 @@ package rest; import dto.ConnectDB; import dto.ScanObj; +import io.quarkus.security.Authenticated; +import org.eclipse.microprofile.rest.client.inject.RestClient; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.slf4j.Logger; @@ -15,6 +17,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +@Authenticated @Path("/startScan") public class CreateStartScan { diff --git a/src/main/java/rest/Scan.java b/src/main/java/rest/Scan.java index 2394c6f..e7e84b4 100644 --- a/src/main/java/rest/Scan.java +++ b/src/main/java/rest/Scan.java @@ -1,8 +1,6 @@ -package rest; +package rest; -import javax.persistence.Entity; - -public class Scan { +public class Scan { private int scanId; private String productId; private String eventId; diff --git a/src/main/java/rest/StoreData.java b/src/main/java/rest/StoreData.java index ae2925e..711f437 100644 --- a/src/main/java/rest/StoreData.java +++ b/src/main/java/rest/StoreData.java @@ -1,91 +1,21 @@ package rest; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Set; -import dto.ScanObj; // import dto.ConnectDB; // import dto.Scan; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.Statement; - -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import java.util.Set; -import java.util.stream.Collectors; -import javax.inject.Inject; -import javax.ws.rs.Consumes; - -import java.sql.*; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; - -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.hibernate.boot.Metadata; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; // import org.hibernate.EntityManager; -import jakarta.persistence.EntityManager; -import jakarta.persistence.Cacheable; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.NamedQuery; -import jakarta.persistence.QueryHint; -import jakarta.persistence.SequenceGenerator; -import jakarta.persistence.Table; - -import org.eclipse.microprofile.rest.client.inject.RestClient; -import dto.ScanObj; - -import javax.inject.Inject; -import javax.validation.Valid; -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PUT; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; -import org.json.JSONObject; -import org.json.JSONArray; -import dto.ScanObj; -import dto.ConnectDB; -import dto.ScanObjPayload; - -import javax.ws.rs.PathParam; - -import static constants.HttpHeaders.AUTHORIZATION_STRING; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.Statement; @Path("/storeData") public class StoreData { diff --git a/src/main/java/rest/UsersResource.java b/src/main/java/rest/UsersResource.java new file mode 100644 index 0000000..f68ce18 --- /dev/null +++ b/src/main/java/rest/UsersResource.java @@ -0,0 +1,36 @@ +package rest; + +import dto.ConnectDB; +import dto.ScanObj; +import io.quarkiverse.kerberos.KerberosPrincipal; +import io.quarkus.security.Authenticated; +import io.quarkus.security.identity.SecurityIdentity; + +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Set; +import javax.ws.rs.Produces; + +@Path("/testKerberos") +@Authenticated +public class UsersResource { + @Inject + SecurityIdentity identity; + @Inject + KerberosPrincipal kerberosPrincipal; + + @GET + @Path("/me") + @Produces("text/plain") + public String me() { + return identity.getPrincipal().getName(); + } +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 9de352c..5edad7b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,4 @@ +#Example deploy - mvn deploy -Dquarkus.profile=stage -Dquarkus.kubernetes.deploy=true # quarkus.rest-client."rest.CreateScanService".url=https://localhost:8080/ # quarkus.rest-client."rest.CreateScanService".scope=javax.inject.Singleton @@ -5,6 +6,35 @@ # couchdb.url=https://localhost:5984 # quarkus.hibernate-orm.database.generation=drop-and-create -quarkus.datasource.devservices.enabled=true -quarkus.datasource.db-kind=postgresql -quarkus.datasource.devservices.volumes."/local/test/data"=/var/lib/postgresql/data + +%dev.quarkus.kerberos.keytab-path= HTTP_osh-pct-security-tooling.apps.ocp-c1.prod.psi.redhat.com@IPA.REDHAT.COM.keytab +%dev.quarkus.kerberos.service-principal-name= HTTP/osh-pct-security-tooling.apps.ocp-c1.prod.psi.redhat.com@IPA.REDHAT.COM + +%stage.quarkus.openshift.name=osh +%stage.quarkus.openshift.labels.env=stage +%stage.quarkus.log.level=DEBUG + +#Only in Quarkus > 3.x +%stage.quarkus.openshift.route.tls.termination=edge +#As we cant create a edge terminated route (quarkus <3.x) lets disable route creation for now +%stage.quarkus.openshift.route.expose=false +%stage.quarkus.openshift.route.target-port=https +%stage.quarkus.openshift.route.tls.insecure-edge-termination-policy=redirect + +########################################## +# Kerberos Specifics # +########################################## +%stage.quarkus.openshift.secret-volumes.osh-wrapper.secret-name=kerberos-keytab-osh +%stage.quarkus.openshift.mounts.osh-wrapper.path=/kerberos +%stage.quarkus.openshift.mounts.osh-wrapper.read-only=true +%stage.quarkus.kerberos.keytab-path= /kerberos/kerberos-keytab-osh +%stage.quarkus.kerberos.service-principal-name= HTTP/osh-pct-security-tooling.apps.ocp-c1.prod.psi.redhat.com@IPA.REDHAT.COM + +%stage.quarkus.openshift.mounts.osh-wrapper-config-vol.path=/etc/krb5.conf +%stage.quarkus.openshift.mounts.osh-wrapper-config-vol.sub-path=linux-krb5.conf +%stage.quarkus.openshift.config-map-volumes.osh-wrapper-config-vol.config-map-name=kerberos-config +%stage.quarkus.openshift.config-map-volumes.osh-wrapper-config-vol.items."linux-krb5.conf".path=linux-krb5.conf +%stage.quarkus.openshift.mounts.osh-wrapper-config-vol.read-only=true + + +