Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6eb05f7

Browse files
Github integration
1 parent 3fbbb7a commit 6eb05f7

8 files changed

Lines changed: 427 additions & 250 deletions

File tree

‎.dockerignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
./.dapper
22
./.cache
33
./dist
4+
./tunnelware
5+
./deploy/secret.yaml

‎deploy/deploy.yaml‎

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,6 @@ metadata:
55
name: tunnel-system
66
---
77
apiVersion: v1
8-
kind: ServiceAccount
9-
metadata:
10-
name: tunnelware
11-
namespace: tunnel-system
12-
---
13-
apiVersion: rbac.authorization.k8s.io/v1
14-
kind: Role
15-
metadata:
16-
name: tunnelware
17-
namespace: tunnel-system
18-
rules:
19-
- apiGroups:
20-
- "networking.k8s.io"
21-
resources:
22-
- 'ingresses'
23-
verbs:
24-
- '*'
25-
- apiGroups:
26-
- "cert-manager.io"
27-
resources:
28-
- 'certificates'
29-
verbs:
30-
- '*'
31-
---
32-
apiVersion: rbac.authorization.k8s.io/v1
33-
kind: RoleBinding
34-
metadata:
35-
name: tunnelware
36-
namespace: tunnel-system
37-
roleRef:
38-
apiGroup: rbac.authorization.k8s.io
39-
kind: Role
40-
name: tunnelware
41-
subjects:
42-
- kind: ServiceAccount
43-
name: tunnelware
44-
namespace: tunnel-system
45-
---
46-
apiVersion: v1
478
kind: Service
489
metadata:
4910
name: tunnelware
@@ -71,7 +32,6 @@ spec:
7132
labels:
7233
app: tunnelware
7334
spec:
74-
serviceAccountName: tunnelware
7535
containers:
7636
- name: tunnelware
7737
image: strongmonkey1992/tunnelware:dev
@@ -84,6 +44,29 @@ spec:
8444
- --debug
8545
ports:
8646
- containerPort: 8080
47+
env:
48+
- name: GITHUB_CLIENT_ID
49+
valueFrom:
50+
secretKeyRef:
51+
name: github-client-secret
52+
key: github-client-id
53+
- name: GITHUB_CLIENT_SECRET
54+
valueFrom:
55+
secretKeyRef:
56+
name: github-client-secret
57+
key: github-client-secret
58+
- name: JWT_SECRET_KEY_PATH
59+
value: "/etc/jwt/private-key"
60+
- name: SERVER_ADDRESS
61+
value: "https://tunnelware.do.rancher.space"
62+
volumeMounts:
63+
- name: jwt-secret
64+
mountPath: "/etc/jwt"
65+
readOnly: true
66+
volumes:
67+
- name: jwt-secret
68+
secret:
69+
secretName: jwt-private-key
8770
---
8871
apiVersion: networking.k8s.io/v1
8972
kind: Ingress
@@ -94,9 +77,20 @@ spec:
9477
ingressClassName: traefik
9578
tls:
9679
- hosts:
80+
- "*.tunnelware.do.rancher.space"
9781
- "tunnelware.do.rancher.space"
9882
secretName: tunnelware-tls
9983
rules:
84+
- http:
85+
paths:
86+
- path: /
87+
pathType: Prefix
88+
backend:
89+
service:
90+
name: tunnelware
91+
port:
92+
number: 80
93+
host: "*.tunnelware.do.rancher.space"
10094
- http:
10195
paths:
10296
- path: /
@@ -120,10 +114,11 @@ spec:
120114
privateKeySecretRef:
121115
name: tunnelware-account
122116
solvers:
123-
- selector: {}
124-
http01:
125-
ingress:
126-
class: traefik
117+
- dns01:
118+
digitalocean:
119+
tokenSecretRef:
120+
name: digitalocean-dns
121+
key: access-token
127122
---
128123
apiVersion: cert-manager.io/v1
129124
kind: Certificate
@@ -134,7 +129,8 @@ spec:
134129
secretName: tunnelware-tls
135130
issuerRef:
136131
name: letsencrypt-production
137-
commonName: tunnelware.do.rancher.space
132+
commonName: "*.tunnelware.do.rancher.space"
138133
dnsNames:
139-
- tunnelware.do.rancher.space
134+
- "*.tunnelware.do.rancher.space"
135+
- "tunnelware.do.rancher.space"
140136

‎go.mod‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,22 @@ module github.com/rancher/tunnelware
33
go 1.13
44

55
require (
6-
github.com/dgraph-io/badger/v3 v3.2011.1
6+
github.com/dgrijalva/jwt-go v3.2.0+incompatible
7+
github.com/google/go-github/v34 v34.0.0
78
github.com/gorilla/mux v1.8.0
89
github.com/jetstack/cert-manager v1.2.0
10+
github.com/onsi/ginkgo v1.12.1
11+
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4
912
github.com/pkg/errors v0.9.1
1013
github.com/rancher/lasso v0.0.0-20210224225615-d687d78ea02a
1114
github.com/rancher/remotedialer v0.2.6-0.20210318171128-d1ebd5202be4
1215
github.com/rancher/wrangler v0.7.3-0.20210319211136-3eba78f45e7d
1316
github.com/rancher/wrangler-cli v0.0.0-20210217230406-95cfa275f52f
1417
github.com/sirupsen/logrus v1.6.0
1518
github.com/spf13/cobra v1.0.0
16-
k8s.io/api v0.19.0
19+
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
20+
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
21+
golang.org/x/tools v0.0.0-20201105001634-bc3cf281b174 // indirect
1722
k8s.io/apimachinery v0.19.0
1823
k8s.io/client-go v0.19.0
1924
)

‎go.sum‎

Lines changed: 6 additions & 34 deletions
Large diffs are not rendered by default.

‎pkg/cmd/client.go‎

Lines changed: 97 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,37 @@ package cmd
22

33
import (
44
"fmt"
5-
"github.com/pkg/errors"
6-
"github.com/rancher/remotedialer"
7-
"github.com/rancher/tunnelware/pkg/rdns"
8-
cli "github.com/rancher/wrangler-cli"
9-
"github.com/rancher/wrangler/pkg/ticker"
10-
"github.com/sirupsen/logrus"
11-
"github.com/spf13/cobra"
12-
"net"
5+
"io/ioutil"
136
"net/http"
147
"net/url"
158
"os"
9+
"os/exec"
1610
"path/filepath"
1711
"strings"
18-
"time"
12+
13+
"github.com/dgrijalva/jwt-go"
14+
"github.com/pkg/browser"
15+
"github.com/pkg/errors"
16+
"github.com/rancher/remotedialer"
17+
"github.com/rancher/tunnelware/pkg/questions"
18+
cli "github.com/rancher/wrangler-cli"
19+
"github.com/rancher/wrangler/pkg/randomtoken"
20+
"github.com/sirupsen/logrus"
21+
"github.com/spf13/cobra"
22+
)
23+
24+
var (
25+
domain = "tunnelware.do.rancher.space"
1926
)
2027

28+
type Claim struct {
29+
Username string `json:"username"`
30+
jwt.StandardClaims
31+
}
32+
2133
func NewClientCommand() *cobra.Command {
2234
client := cli.Command(&Client{}, cobra.Command{
23-
Short: "Run tunnel client",
35+
Short: "Run tunnel client",
2436
Example: " tunnelware client http 8080",
2537
})
2638
return client
@@ -43,54 +55,100 @@ func (c *Client) Run(cmd *cobra.Command, args []string) error {
4355
if err != nil {
4456
return err
4557
}
46-
4758
if err := os.MkdirAll(filepath.Join(homedir, ".tunnelware"), 0755); err != nil {
4859
return err
4960
}
5061

51-
u, err := url.Parse(c.Server)
52-
if err != nil {
53-
return err
54-
}
62+
tokenFile := filepath.Join(homedir, ".tunnelware", "token")
63+
if _, err := os.Stat(filepath.Join(homedir, ".tunnelware", "token")); err != nil {
64+
// request auth token
65+
state, err := randomtoken.Generate()
66+
if err != nil {
67+
return err
68+
}
5569

56-
rdnsClient := rdns.NewClient()
70+
serverURL, err := url.Parse(c.Server)
71+
if err != nil {
72+
return err
73+
}
5774

58-
domain, err := rdns.GetDomain(cmd.Context(), rdnsClient, []string{u.Hostname()}, net.ParseIP(u.Hostname()) == nil)
59-
if err != nil {
60-
return err
61-
}
62-
go func() {
63-
for range ticker.Context(cmd.Context(), time.Hour * 6) {
64-
if _, err := rdnsClient.RenewDomain(); err != nil {
65-
logrus.Error(err)
75+
url := fmt.Sprintf("https://%s/login/github?state=%s", serverURL.Host, state)
76+
fmt.Printf("Redirecting to %v for github login\n", url)
77+
// credit from https://github.com/hashicorp/terraform/pull/24107/files
78+
// Windows Subsystem for Linux (bash for Windows) doesn't have xdg-open available
79+
// but you can execute cmd.exe from there; try to identify it
80+
if !hasProgram("xdg-open") && hasProgram("cmd.exe") {
81+
r := strings.NewReplacer("&", "^&")
82+
if out, err := exec.Command("cmd.exe", "/c", "start", r.Replace(url)).Output(); err != nil {
83+
return errors.Wrap(err, string(out))
84+
}
85+
} else {
86+
if err := browser.OpenURL(url); err != nil {
87+
return err
6688
}
6789
}
68-
}()
6990

70-
clientID := strings.Split(domain, ".")[0]
91+
finished, err := questions.PromptBool("Once you finish github login, enter y to continue", true)
92+
if err != nil {
93+
return err
94+
}
95+
if !finished {
96+
return nil
97+
}
98+
resp, err := http.Get(fmt.Sprintf("https://%s/jwt/%s", serverURL.Host, state))
99+
if err != nil {
100+
return err
101+
}
102+
defer resp.Body.Close()
103+
token, err := ioutil.ReadAll(resp.Body)
104+
if err != nil {
105+
return err
106+
}
107+
if err := ioutil.WriteFile(tokenFile, token, 0755); err != nil {
108+
return err
109+
}
110+
}
71111

72-
headers := http.Header{
73-
"X-Tunnel-ID": []string{clientID},
112+
token, err := ioutil.ReadFile(tokenFile)
113+
if err != nil {
114+
return err
74115
}
75116

76-
query := u.Query()
77-
query.Add("fqdn", domain)
117+
claim := &Claim{}
118+
if _, err := jwt.ParseWithClaims(string(token), claim, nil); err != nil {
119+
if err.(*jwt.ValidationError).Errors != jwt.ValidationErrorUnverifiable {
120+
return err
121+
}
122+
}
123+
124+
u, err := url.Parse(c.Server)
125+
if err != nil {
126+
return err
127+
}
78128
scheme := args[0]
79-
host := args[1]
80-
if !strings.Contains(host, ":") {
81-
host = fmt.Sprintf("%v://127.0.0.1:%v", scheme, host)
129+
forwardHost := args[1]
130+
if !strings.Contains(forwardHost, ":") {
131+
forwardHost = fmt.Sprintf("%v://127.0.0.1:%v", scheme, forwardHost)
82132
} else {
83-
host = fmt.Sprintf("%v://%v", scheme, host)
133+
forwardHost = fmt.Sprintf("%v://%v", scheme, forwardHost)
84134
}
85-
query.Add("forward", host)
86-
u.RawQuery = query.Encode()
87135

88-
logrus.Debugf("connecting to %v", u.String())
136+
headers := http.Header{
137+
"X-TUNNEL-ID": []string{fmt.Sprintf("%s:%s", strings.ToLower(claim.Username), forwardHost)},
138+
"Authorization": []string{"Bearer " + string(token)},
139+
}
89140

141+
logrus.Debugf("connecting to %v", u.String())
142+
domainWithUsername := fmt.Sprintf("%s.%s", strings.ToLower(claim.Username), domain)
90143
go func() {
91-
fmt.Printf("http://%v --------> %v\nhttps://%v -------> %v\n", domain, host, domain, host)
144+
fmt.Printf("http://%v --------> %v\nhttps://%v -------> %v\n", domainWithUsername, forwardHost, domainWithUsername, forwardHost)
92145
remotedialer.ClientConnect(cmd.Context(), u.String(), headers, nil, func(string, string) bool { return true }, nil)
93146
}()
94-
<-cmd.Context().Done()
147+
<-cmd.Context().Done()
95148
return nil
96149
}
150+
151+
func hasProgram(name string) bool {
152+
_, err := exec.LookPath(name)
153+
return err == nil
154+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /