/
main.go
109 lines (87 loc) · 2.28 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package main
import (
"context"
"crypto/tls"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"time"
"github.com/gin-gonic/gin"
"github.com/patrickmn/go-cache"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
proxySecretName = "crane-proxy"
)
type Cluster struct {
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`
}
func main() {
config, err := rest.InClusterConfig()
if err != nil {
log.Fatalf("Unable to retrieve in cluster kubeconfig.")
}
gocache := cache.New(5*time.Minute, 10*time.Minute)
client, err := client.New(config, client.Options{})
if err != nil {
log.Fatalf("Unable to create kubernetes client.")
}
r := gin.Default()
r.SetTrustedProxies(nil)
r.Any("/:namespace/:name/*proxyPath", func(c *gin.Context) {
var proxy *httputil.ReverseProxy
namespace, _ := c.Params.Get("namespace")
name, _ := c.Params.Get("name")
url := getClusterURL(client, gocache, namespace, name)
if url != nil {
proxy = httputil.NewSingleHostReverseProxy(url)
}
if proxy == nil {
c.AbortWithStatus(http.StatusBadGateway)
} else {
proxy.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
proxy.FlushInterval = 0
c.Request.URL.Path, _ = c.Params.Get("proxyPath")
c.Request.Host = url.Host
proxy.ServeHTTP(c.Writer, c.Request)
if c.Writer.Status() >= http.StatusBadRequest {
gocache.Delete(namespace + name)
}
}
})
crt := os.Getenv("CRANE_PROXY_CRT")
key := os.Getenv("CRANE_PROXY_KEY")
if crt == "" || key == "" {
log.Fatalf("Export CRANE_PROXY_CRT and CRANE_PROXY_KEY before running.")
}
r.RunTLS(":8443", crt, key)
}
func getClusterURL(client client.Client, gocache *cache.Cache, namespace string, name string) *url.URL {
cachedRemote, found := gocache.Get(namespace + name)
if found {
return cachedRemote.(*url.URL)
}
ref := types.NamespacedName{
Namespace: namespace,
Name: name,
}
secret := v1.Secret{}
err := client.Get(context.TODO(), ref, &secret)
if err != nil {
return nil
}
remote, err := url.Parse(string(secret.Data["url"]))
if err != nil {
return nil
}
gocache.Set(namespace+name, remote, cache.DefaultExpiration)
return remote
}