Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document Airgap Setup for Maven #15503

Closed
tsmaeder opened this issue Dec 17, 2019 · 5 comments
Closed

Document Airgap Setup for Maven #15503

tsmaeder opened this issue Dec 17, 2019 · 5 comments
Assignees
Labels
area/languages Issues related to Language extensions or plugins integration. kind/task Internal things, technical debt, and to-do tasks to be performed. severity/P1 Has a major impact to usage or development of the system.

Comments

@tsmaeder
Copy link
Contributor

tsmaeder commented Dec 17, 2019

Test and document the process of setting up an airgap solution for Maven. In particular, configure a workspace based on our default maven devfile to use a Maven repository that uses a self-signed certificate.

The following issues are related and we need to document how to solve them manuall in this issue:

@tsmaeder tsmaeder added the kind/task Internal things, technical debt, and to-do tasks to be performed. label Dec 17, 2019
@l0rd l0rd added severity/P1 Has a major impact to usage or development of the system. area/languages Issues related to Language extensions or plugins integration. team/languages labels Dec 17, 2019
@tsmaeder tsmaeder mentioned this issue Dec 18, 2019
28 tasks
@tsmaeder tsmaeder added this to the Backlog - Languages milestone Dec 18, 2019
@tsmaeder tsmaeder mentioned this issue Jan 8, 2020
35 tasks
@sunix sunix self-assigned this Jan 17, 2020
@tsmaeder tsmaeder mentioned this issue Jan 23, 2020
36 tasks
@sunix
Copy link
Contributor

sunix commented Jan 29, 2020

Here, I am describing how we could setup Maven to use a private Artifact repository in the case where Che could not access the internet and Maven Central.

There are several options:

  • Artifact repositories are defined in a pom.xml file (parent or not) of the project.
  • Artifact repositories are defined in settings.xml: in traditional desktop installation it would be ~/.m2/settings.xml
  • Private repos with https and self-signed certificate

Setup the environment

Setup Nexus

Here, I will describe how I install Nexus to test my configuration. The Nexus will be installed through an operator in Openshift 4.2.

Install the operator

From the the openshift 4.2 console, as an admin, 

  • Create a airgap project,

  • install nexus3 operator from the operatorhub
    image

  • Create Nexus by going to Installed Operators and the Nexus tab
    image

  • Once nexus is started, access to nexus

    image

  • Login as admin, you can get to the generated admin password which is located in /nexus-data/admin.password of the nexus pod

  • Change the admin password from nexus profile.

Upload artifacts of our project.

  • Download https://github.com/redhat-developer-demos/quarkus-reactjs-postit-app/releases/download/20191216-local/local.zip that contains all the artifacts for our project.
  • Go to the folder m2repo
  • Run the the command (replacing and with the right values). Run the command 1 time for maven-snapshot and another time for maven-release. The URLs could be retrieve from Nexus console:
    image
    find . -type f -not -path '*/\.*' -not -path '*/\^archetype\-catalog\.xml*' -not -path '*/\^maven\-metadata\-local*\.xml' -not -path '*/\^maven\-metadata\-deployment*\.xml' | sed "s|^\./||" | xargs -I '{}' curl -u "admin:<ADMINPASSWORD>" -X PUT -v -T {} <URL>{} ;
    

Start the test workspace

Start a workspace from this devfile: https://gist.githubusercontent.com/sunix/4bcef770db4985b5b768a6c81ab9f82c/raw/devfile.yaml

This devfile will set user.home to /project for the quarkus-backend-dev container.

Disconnect from central.

My cluster is connected to the internet, to fake disconnection from the internet, I am disabling central repo in the project pom.xml.

Edit the pom.xml and add:

    [...]
    </profile>
  </profiles>
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <url>http://nowhere</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </pluginRepository>
  </pluginRepositories>
  <repositories>
    <repository>
       <id>central</id>
       <releases>
         <enabled>false</enabled>
       </releases>
       <snapshots>
         <enabled>false</enabled>
       </snapshots>
       <url>http://nowhere</url>
    </repository>
  </repositories>
</project>

That will disable central

Clean the folder /project/.m2/repository from the quarkus-backend-dev container:

rm /project/.m2/repository -rf

Now if you run the command build JVM quarkus-backend, it should fail.

Same opening Post.java file should start the language server then, shows errors in pom.xml.

image

Configure Maven to use a remote repository

Define repositories in pom.xml

The first way to setup our internal nexus repo to be used by our project is to set the repo in the pom.xml file (could also be a parent pom.xml).

Copy the maven-releases and maven-snapshots URLs and add the repositories with the right URLs:
image

  </profiles>
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <url>http://nowhere</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </pluginRepository>
    <pluginRepository>
       <id>my-nexus-snapshots</id>
       <releases>
         <enabled>false</enabled>
       </releases>
       <snapshots>
         <enabled>true</enabled>
       </snapshots>
       <url>http://nexus3-airgap.apps.acme.com/repository/maven-snapshots/</url>
    </pluginRepository>
    <pluginRepository>
       <id>my-nexus-releases</id>
       <releases>
         <enabled>true</enabled>
       </releases>
       <snapshots>
         <enabled>false</enabled>
       </snapshots>
       <url>http://nexus3-airgap.apps.acme.com/repository/maven-releases/</url>
    </pluginRepository>
  </pluginRepositories>
  <repositories>
    <repository>
       <id>central</id>
       <releases>
         <enabled>false</enabled>
       </releases>
       <snapshots>
         <enabled>false</enabled>
       </snapshots>
       <url>http://nowhere</url>
    </repository>
    <repository>
       <id>my-nexus-snapshots</id>
       <releases>
         <enabled>false</enabled>
       </releases>
       <snapshots>
         <enabled>true</enabled>
       </snapshots>
       <url>http://nexus3-airgap.apps.acme.com/repository/maven-snapshots/</url>
    </repository>
    <repository>
       <id>my-nexus-releases</id>
       <releases>
         <enabled>true</enabled>
       </releases>
       <snapshots>
         <enabled>false</enabled>
       </snapshots>
       <url>http://nexus3-airgap.apps.acme.com/repository/maven-releases/</url>
    </repository>
  </repositories>
</project>

Checking Language Server

Adding these lines to the pom.xml should fix the errors of the pom.xml.

Checking Maven command line

Clean the folder /project/.m2/repository from the quarkus-backend-dev container:

rm /project/.m2/repository -rf

Now if you run the command package JVM quarkus-backend should succeed.

Define repositories in settings.xml

The second way to setup our internal nexus repo to be used by our project is to set the repo in the HOME/.m2/settings.xml file. Unfortunately, this is not something we can inject from the devfile (see Injecting settings.xml). However it works, if you create it after the first workspace loading and still painful to recreate it each time a workspace is recreated.

Revert the changes done in the previous section (keep the override of maven central).

Clean the folder /project/.m2/repository from the quarkus-backend-dev container:

rm /project/.m2/repository -rf

Make sure errors appears again when running the package command or openning the pom.xml

Create a settings.xml file from the quarkus-backend-dev container (change the URLs):

cat <<EOF > /project/.m2/settings.xml
<settings>
  <profiles>
    <profile>
      <id>my-nexus</id>
      <pluginRepositories>
        <pluginRepository>
           <id>my-nexus-snapshots</id>
           <releases>
             <enabled>false</enabled>
           </releases>
           <snapshots>
             <enabled>true</enabled>
           </snapshots>
           <url>http://nexus3-airgap.apps.acme.com/repository/maven-snapshots/</url>
        </pluginRepository>
        <pluginRepository>
           <id>my-nexus-releases</id>
           <releases>
             <enabled>true</enabled>
           </releases>
           <snapshots>
             <enabled>false</enabled>
           </snapshots>
           <url>http://nexus3-airgap.apps.acme.com/repository/maven-releases/</url>
        </pluginRepository>
      </pluginRepositories>
      <repositories>
        <repository>
           <id>my-nexus-snapshots</id>
           <releases>
             <enabled>false</enabled>
           </releases>
           <snapshots>
             <enabled>true</enabled>
           </snapshots>
           <url>http://nexus3-airgap.apps.acme.com/repository/maven-snapshots/</url>
        </repository>
        <repository>
           <id>my-nexus-releases</id>
           <releases>
             <enabled>true</enabled>
           </releases>
           <snapshots>
             <enabled>false</enabled>
           </snapshots>
           <url>http://nexus3-airgap.apps.acme.com/repository/maven-releases/</url>
        </repository>
      </repositories>
    </profile>
  </profiles>
  <activeProfiles>
    <activeProfile>my-nexus</activeProfile>
  </activeProfiles>
</settings>
EOF

Checking Language Server

Clean the folder /project/.m2/repository from the quarkus-backend-dev container:

rm /project/.m2/repository -rf

Open Post.java should start the language server (if not restart, make a change in pom.xml to trigger the build). No error should appear.

Checking Maven command line

Clean the folder /project/.m2/repository from the quarkus-backend-dev container:

rm /project/.m2/repository -rf

Now if you run the command package JVM quarkus-backend should succeed.

Setup TLS with self signed certificate for Nexus

Configure Nexus with TLS and self-signed certificate

We are going to add a new route with tls and a self signed certificate that we create:

Create the certificate (adapt the CN with your hostname)

openssl req -x509 -newkey rsa:4096 -sha256 -days 365 -nodes \
  -keyout tls.key -out tls.crt -subj '/CN=acme.com' \
  -addext 'subjectAltName=DNS:*.apps.acme.com'

or if openssl version < 1.1.1

openssl req -x509 -newkey rsa:4096 -sha256 -days 365 -nodes   -keyout tls.key -out tls.crt -subj '/CN=acme.com' \
  -extensions san \
  -config <(echo '[req]'; echo 'distinguished_name=req';
            echo '[san]'; echo 'subjectAltName=DNS:*.apps.acme.com')

Notes:

Create a new route in the project where the nexus operator cluster is deployed:

$ oc project airgap
$ oc create route edge snexus --service=nexus3 --cert=tls.crt --key=tls.key
$ oc describe Route snexus

Name:			snexus
Namespace:		airgap
Created:		14 seconds ago
Labels:			app=nexus3
Annotations:		openshift.io/host.generated=true
Requested Host:		snexus-airgap.apps.acme.com
			  exposed on router default (host apps.acme.com) 14 seconds ago
Path:			<none>
TLS Termination:	edge
Insecure Policy:	<none>
Endpoint Port:		http

Service:	nexus3
Weight:		100 (100%)
Endpoints:	10.128.2.18:8081

Change in settings.xml all the URLs and use https://snexus-airgap.apps.acme.com as a base host of each URLs.

Executing a build after having cleaned up the repo should fail:
image

Configure Maven to use the Secured Nexus (with self-signed certificate)

Steps to configure maven to trust our certificate:

  • Create a Java truststore with the certificate
  • Upload it so it is available in the containers
  • Tell Maven to use it

Create truststore

$ keytool -import -file tls.crt -alias nexus -keystore truststore.jks -storepass changeit

Trust this certificate? [no]:  yes
Certificate was added to keystore
Owner: CN=acme.com
Issuer: CN=acme.com
Serial number: 80ca0f6980c6019a
Valid from: Thu Feb 06 11:00:29 CET 2020 until: Fri Feb 05 11:00:29 CET 2021
Certificate fingerprints:
	 MD5:  88:3C:EC:E1:BE:57:DD:9D:46:36:8E:DD:BF:14:04:22
	 SHA1: 08:D8:79:D3:F8:6B:5C:3D:71:AA:23:CA:72:01:47:BD:9D:91:0A:AD
	 SHA256: 5C:BB:66:81:44:D2:50:EE:EB:CE:D6:15:7E:63:E1:9A:71:EA:58:3F:14:01:15:4E:68:5D:71:0A:A0:31:33:29
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: *.apps.acme.com
]

Trust this certificate? [no]:  yes
Certificate was added to keystore

Once created upload it in /projects (so it is available to all the containers)
image

Checking command line

To have it working from our build JVM quarkus-backend (that would actually perform a mvn package), we need to tell maven where to find the certificate. In the devfile, I have added to the environment variable MAVEN_OPTS:

    env:
      - value: '-Duser.home=/project -Djavax.net.ssl.trustStore=/projects/truststore.jks'
        name: MAVEN_OPTS

image

And restarting the workspace, it works:
image

Checking Language Server

The embedded maven does not seem to rely on MAVEN_OPTS. I have tried to add the option in the preferences.
From the devfile:

[...]
  - alias: java
    type: chePlugin
    id: redhat/java/latest
    memoryLimit: 1536M
    preferences:
      java.jdt.ls.vmargs: >-
        -noverify -Xmx1G -XX:+UseG1GC -XX:+UseStringDeduplication
        -Djavax.net.ssl.trustStore=/projects/truststore.jks  
[...]

Related issue:

redhat-developer/vscode-java#455

Concerns and issues

To summarize:
  • Private repos defined in project (or parent) pom.xml: OK
  • Private repos defined in settings.xml: OK but need additional manual steps
  • Private repos accessible through HTTPS with self signed certificate
    • Maven CLI (in runtime container): OK but need additional manual steps (to inject the truststore file)
    • JDT.ls OK but need additional manual steps (to inject the truststore)

Injecting settings.xml

Unfortunately, there is no way to inject a settings.xml file from the devfile.

eclipse-che/che-theia#429 is not usable: it only deals with one external mirror where most of the customers may have more than just mirrors to configure their airgap in settings.xml:

  • user/password to access to internal server (repositories)
  • Several private repos and configurations
  • Several mirrors

Che should allow injecting such files or environment variable through the devfile with secrets maybe. This kind of config files may need to be shared across an organisation (team, BU). Some other files would be more personal

Related issue that may need to be reprioritized:

Self signed certificate

At some point we would need to inject the truststore. Maybe #15218 and/or kubernetes secrets #14680 are good starting points.

#14680 would be nice. It could also be secrets that would be shared by several users of the same organisation. I would NOT recommend adding the file contents in the devfile (though it would be useful for testing purposes). These files would generally contain token, password, sensitive information that should not be shared in a git repo. So a devfile is not appropriate. However in the devfile defining which secret should be used to inject some files or environment variable would be nice. Also being able to set the secrets from a UI like the user dashboard would be nice.

VSCode extension preferences: in devfile our in the user preferences ?

I am not sure vscode extension preferences is something the user would like to configure in the devfile. Instead, user may want to configure that once in the user preferences.

Working devfile sample

This devfile: https://gist.github.com/sunix/00f890965f04620139e616fbcba75444, is setting up a workspace with a maven project that would work with a private nexus repository.
As workarounds of the previous issues:

  • There is a zip file that will be downloaded and unzipped in /projects. It contains a settings.xml, the trustore file.
  • A command to copy the settings.xml in the right folder

@snjeza
Copy link
Contributor

snjeza commented Jan 31, 2020

@sunix
Copy link
Contributor

sunix commented Feb 7, 2020

@sunix see redhat-developer/vscode-java#455 (comment)

Thanks, I have updated the previous doc

@slemeur
Copy link
Contributor

slemeur commented Feb 17, 2020

@rkratky : We need to put this into the documentation. Would you be able to take that into account for 7.9 ?

@slemeur
Copy link
Contributor

slemeur commented Feb 17, 2020

@rhopp and @dmytro-ndp : This is important capabilities. we should have automated tests for this. Is that something you can work on?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/languages Issues related to Language extensions or plugins integration. kind/task Internal things, technical debt, and to-do tasks to be performed. severity/P1 Has a major impact to usage or development of the system.
Projects
None yet
Development

No branches or pull requests

5 participants