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

Test and Document Airgap Setup for Go #15512

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

Test and Document Airgap Setup for Go #15512

tsmaeder opened this issue Dec 17, 2019 · 2 comments
Labels
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

Test and document the process of setting up an airgap solution for Go. In particular, configure a workspace based on our default go devfile to work in an air-gapped scenario (i.e. dependencies being fetched from a repository in the company network. No idea if this is even possible.

@tsmaeder tsmaeder added the kind/task Internal things, technical debt, and to-do tasks to be performed. label Dec 17, 2019
@che-bot che-bot added the status/need-triage An issue that needs to be prioritized by the curator responsible for the triage. See https://github. label Dec 17, 2019
@l0rd l0rd added severity/P1 Has a major impact to usage or development of the system. team/languages and removed status/need-triage An issue that needs to be prioritized by the curator responsible for the triage. See https://github. labels Dec 17, 2019
@tsmaeder tsmaeder mentioned this issue Dec 18, 2019
28 tasks
@tsmaeder tsmaeder mentioned this issue Jan 8, 2020
35 tasks
@tsmaeder tsmaeder mentioned this issue Jan 23, 2020
36 tasks
@JPinkney
Copy link
Contributor

JPinkney commented Feb 6, 2020

Golang Airgapped

The way we are going to set up airgapped golang is using golang’s GOPROXY env variable and using Athens [1]. Athens is an "A Go module datastore and proxy” with great configurability that will give us a place to upload our Go modules too. Since Athens is highly configurable, we are going to set it up so that it acts only as a module datastore and not as a proxy. Essentially, we are going to make it so that an admin can upload their Go modules to this datastore and have them available for their teams Go projects, but once they try and access a Go module that is not in the datastore their Go build will fail.

Installing Athens

To start we need to configure Athens, which I will be deploying on minikube via a helm chart.
This part essentially is just following: https://docs.gomods.io/install/install-on-kubernetes/ with a few minor modifications (mostly creation of an ingress and a setting change so that if a module is not found in the datastore it will not contact any VCS).

$ helm repo add gomods https://athens.blob.core.windows.net/charts
$ helm repo update
$ helm install gomods/athens-proxy -n athens --namespace athens

This will deploy a single instance of athens into the athens namespace.

The rest of the modifications will be done through the minikube dashboard.

When we are at the minikube dashboard we want to modify the athens-athens-proxy deployment by adding the environment variable ATHENS_DOWNLOAD_MODE and setting it to none [2]. This is going to stop athens from trying to connect to a VCS if a Go module is not found in the datastore.

The main dashboard in minikube
2020-02-06-100441_1872x560_scrot

Setting ATHENS_DOWNLOAD_MODE to none
2020-02-06-100510_841x799_scrot

Adding an ingress so Athens is accessible to Che

Next I'm going to create an ingress so that we have something we can set the GOPROXY env variable to inside of Che. Inside of the athens namespace add this YAML:

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: athens-ingress
  namespace: athens
spec:
  rules:
    - host: athens-athens.192.168.0.0.nip.io # Change me if you would like
      http:
        paths:
          - path: /
            backend:
              serviceName: athens-athens-proxy
              servicePort: 80

This will make athens available at athens-athens.192.168.0.0.nip.io. To test that out just visit athens-athens.192.168.0.0.nip.io in your browser and you should see "Welcome to The Athens Proxy".

Preloading Athens with Go modules

The last thing we need to do is load up Athens with all of our modules.

To do this find the athens-athens-proxy pod and open a terminal in it and run these commands

$ cd  /var/lib/athens
$ wget https://github.com/JPinkney/module-storage/archive/master.zip
$ unzip master.zip
$ mv module-storage-master/github.com/ .
$ mv module-storage-master/golang.org/ .
$ mv module-storage-master/rsc.io/ .
$ rm master.zip
$ rm -rf module-storage-master

This is pre-loading all of our Go modules into the athens disk. To learn more see [3] .

Now athens is fully configured so that if a Go module is not in storage it will return a 404 and do nothing, we have an ingress that we can pass as an env variable in a Go devfile, and we have pre-loaded all of the Go modules our project needs.

Connecting to Athens from within Che

Now everything from now on is Che side!

Use this devfile and start a workspace:

metadata:
  generateName: golang-
projects:
  - name: Go-airgap-sample
    source:
      location: 'https://github.com/JPinkney/Go-airgap-sample.git'
      type: git
components:
  - id: ms-vscode/go/latest
    memoryLimit: 512Mi
    type: chePlugin
    alias: go-plugin
  - mountSources: true
    endpoints:
      - name: 8080/tcp
        port: 8080
    memoryLimit: 512Mi
    type: dockerimage
    alias: go-cli
    image: 'quay.io/eclipse/che-golang-1.12:7.7.0'
    env:
      - value: /tmp/.cache
        name: GOCACHE
      - value: 'http://athens-athens.192.168.0.0.nip.io'
        name: GOPROXY
  - id: eclipse/che-theia/next
    type: cheEditor
apiVersion: 1.0.0

Then when your che workspace has loaded open up a go-cli terminal.

$ cd Go-airgap-sample/src/sample/
$ GO111MODULE=on
$ go test

On the first run you should see output similiar to:

bash-4.4 /projects/Go-airgap-sample/src/sample $ go test
go: finding github.com/jpinkney/hello v1.0.0
go: finding rsc.io/quote v1.5.2
go: finding rsc.io/sampler v1.3.0
go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go: downloading github.com/jpinkney/hello v1.0.0
go: extracting github.com/jpinkney/hello v1.0.0
go: downloading rsc.io/quote v1.5.2
go: extracting rsc.io/quote v1.5.2
go: downloading rsc.io/sampler v1.3.0
go: extracting rsc.io/sampler v1.3.0
go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go: extracting golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
PASS
ok      sample  0.002s
bash-4.4 /projects/Go-airgap-sample/src/sample $ 

Now if we modify hello.go to add a new import

package hello

import "github.com/jpinkney/hello"
import "github.com/google/go-cmp/cmp"

func hello2() string {
	return hello.Hello()
}

func main() {
	hello2()
	fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}

and trying to run go get on that module results in:

ash-4.4 /projects/Go-airgap-sample/src/sample $ go get -u github.com/google/go-cmp/cmp
go: finding github.com/google/go-cmp v0.4.0
go get github.com/google/go-cmp/cmp: unexpected status (http://athens-athens.192.168.122.151.nip.io/github.com/google/go-cmp/cmp/@v/list): 404 Not Found

We are getting a 404 Not found error because when we set ATHENS_DOWNLOAD_MODE to none, when a Go module is not found in Athens it will just return a 404.

[1] - https://github.com/gomods/athens
[2] - https://docs.gomods.io/configuration/download/
[3] - https://docs.gomods.io/configuration/prefill-disk-cache/

Setup with self signed certificates

  1. Follow https://www.eclipse.org/che/docs/che-7/setup-che-in-tls-mode-with-self-signed-certificate/#gerenating-self-signed-certificates_setup-che-in-tls-mode-with-self-signed-certificate to generate a self signed certificate.

  2. Then follow https://www.eclipse.org/che/docs/che-7/setup-che-in-tls-mode-with-self-signed-certificate/#deploy-che-with-self-signed-tls-on-kubernetes_setup-che-in-tls-mode-with-self-signed-certificate. The most important step of this process is creating the kubernetes secret.

  3. Install athens in the che namespace

helm install gomods/athens-proxy -n athens --namespace che

This is so we can use the kubernetes secret created in step 2.

  1. Set ATHENS_DOWNLOAD_MODE to none (same as without self signed certificate instruction)

  2. Use this YAML to create the ingress:

kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: athens
  namespace: che
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/proxy-connect-timeout: '3600'
    nginx.ingress.kubernetes.io/proxy-read-timeout: '3600'
    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec:
  tls:
    - hosts:
        - athens-che.${MY_MINIKUBE_IP}.nip.io
      secretName: che-tls
  rules:
    - host: athens-che.${MY_MINIKUBE_IP}.nip.io
      http:
        paths:
          - backend:
              serviceName: athens-athens-proxy
              servicePort: 80

Replace ${MY_MINIKUBE_IP} with your minikube ip

This is going to create an ingress for athens and use the che-tls secret that we created in step 2 for getting the self signed certificate.

  1. Then we are going to start a Che workspace with this devfile:
metadata:
  generateName: golang-
projects:
  - name: Go-airgap-sample
    source:
      location: 'https://github.com/JPinkney/Go-airgap-sample.git'
      type: git
components:
  - id: ms-vscode/go/latest
    memoryLimit: 512Mi
    type: chePlugin
    alias: go-plugin
  - mountSources: true
    endpoints:
      - name: 8080/tcp
        port: 8080
    memoryLimit: 512Mi
    type: dockerimage
    alias: go-cli
    image: 'quay.io/eclipse/che-golang-1.12:7.7.0'
    env:
      - value: /tmp/.cache
        name: GOCACHE
      - value: 'https://athens-che.${MY_MINIKUBE_IP}.nip.io'
        name: GOPROXY
  - id: eclipse/che-theia/next
    type: cheEditor
apiVersion: 1.0.0

where MY_MINIKUBE_IP is replaced with your minikube ip.

  1. Now we need to upload our root cert to the project. Right click on the project explorer and use Upload files to upload the rootCA.crt to the root of the project. (/projects/rootCA.crt)

  2. Inside of the terminal run the commands:

$ export GO111MODULE=on
$ export SSL_CERT_FILE=/projects/rootCA.crt
$ go test

and you will see an output similiar to:

bash-4.4 /projects/Go-airgap-sample/src/sample $ go test
go: finding github.com/jpinkney/hello v1.0.0
go: finding rsc.io/quote v1.5.2
go: finding rsc.io/sampler v1.3.0
go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go: downloading github.com/jpinkney/hello v1.0.0
go: extracting github.com/jpinkney/hello v1.0.0
go: downloading rsc.io/quote v1.5.2
go: extracting rsc.io/quote v1.5.2
go: downloading rsc.io/sampler v1.3.0
go: extracting rsc.io/sampler v1.3.0
go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go: extracting golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
PASS
ok      sample  0.002s

@tsmaeder
Copy link
Contributor Author

What about self-signed certs? The config above does not use https://.

@tsmaeder tsmaeder mentioned this issue Feb 18, 2020
34 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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

4 participants