Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c887d6d
Showing
17 changed files
with
496 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, build with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
# Binary | ||
cmd/prometheus-multi-tenant-proxy/prometheus-multi-tenant-proxy |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
FROM golang:1.12-alpine as builder | ||
|
||
ENV GO111MODULE=on | ||
ENV CGO_ENABLED=0 | ||
|
||
RUN apk add -U --no-cache git ca-certificates && \ | ||
mkdir -p src/github.com/angelbarrera92/prometheus-multi-tenant-proxy | ||
|
||
WORKDIR /go/src/github.com/angelbarrera92/prometheus-multi-tenant-proxy | ||
|
||
COPY go.mod go.mod | ||
COPY go.sum go.sum | ||
COPY cmd cmd | ||
COPY internal internal | ||
|
||
RUN cd cmd/prometheus-multi-tenant-proxy && \ | ||
go build . | ||
|
||
FROM scratch | ||
|
||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ | ||
COPY --from=builder /go/src/github.com/angelbarrera92/prometheus-multi-tenant-proxy/cmd/prometheus-multi-tenant-proxy/prometheus-multi-tenant-proxy /prometheus-multi-tenant-proxy | ||
|
||
ENTRYPOINT [ "/prometheus-multi-tenant-proxy" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/angelbarrera92/prometheus-multi-tenant-proxy/internal/app/prometheus-multi-tenant-proxy" | ||
"github.com/urfave/cli" | ||
) | ||
|
||
var ( | ||
version = "dev" | ||
commit = "none" | ||
date = "unknown" | ||
) | ||
|
||
func main() { | ||
app := cli.NewApp() | ||
app.Name = "Prometheus Multitenant Proxy" | ||
app.Usage = "Makes your Prometheus server multi tenant" | ||
app.Version = version | ||
app.Author = "Ángel Barrera - @angelbarrera92" | ||
app.Commands = []cli.Command{ | ||
{ | ||
Name: "run", | ||
Usage: "Runs the Prometheus multi tenant proxy", | ||
Action: proxy.Serve, | ||
Flags: []cli.Flag{ | ||
cli.IntFlag{ | ||
Name: "port", | ||
Usage: "Port to expose this prometheus proxy", | ||
Value: 9092, | ||
}, cli.StringFlag{ | ||
Name: "prometheus-label-proxy-endpoint", | ||
Usage: "Prometheus Label Proxy", | ||
Value: "http://localhost:9091", | ||
}, cli.StringFlag{ | ||
Name: "auth-config", | ||
Usage: "AuthN yaml configuration file path", | ||
Value: "authn.yaml", | ||
}, | ||
}, | ||
}, | ||
} | ||
app.Run(os.Args) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
users | ||
- username: User | ||
password: Prom | ||
namespace: tenant-1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
users: | ||
- username: User-a | ||
password: pass-a | ||
namespace: tenant-a | ||
- username: User-b | ||
password: pass-b | ||
namespace: tenant-b |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
users: | ||
- username: Happy | ||
password: Prometheus | ||
namespace: default | ||
- username: Sad | ||
password: Prometheus | ||
namespace: kube-system |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
apiVersion: v1 | ||
data: | ||
authn.yaml: dXNlcnM6CiAgLSB1c2VybmFtZTogSGFwcHkKICAgIHBhc3N3b3JkOiBQcm9tZXRoZXVzCiAgICBuYW1lc3BhY2U6IGRlZmF1bHQKICAtIHVzZXJuYW1lOiBTYWQKICAgIHBhc3N3b3JkOiBQcm9tZXRoZXVzCiAgICBuYW1lc3BhY2U6IGt1YmUtc3lzdGVtCg== | ||
kind: Secret | ||
metadata: | ||
labels: | ||
application: prometheus-multitenant-proxy | ||
name: prometheus-auth-config | ||
namespace: default | ||
--- | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
labels: | ||
application: prometheus-multitenant-proxy | ||
name: prometheus-multitenant-proxy | ||
namespace: default | ||
spec: | ||
replicas: 1 | ||
strategy: | ||
type: Recreate | ||
selector: | ||
matchLabels: | ||
application: prometheus-multitenant-proxy | ||
template: | ||
metadata: | ||
labels: | ||
application: prometheus-multitenant-proxy | ||
spec: | ||
volumes: | ||
- name: prometheus-auth-config | ||
secret: | ||
secretName: prometheus-auth-config | ||
containers: | ||
- name: prometheus-multitenant-proxy | ||
image: angelbarrera92/prometheus-multi-tenant-proxy:dev | ||
imagePullPolicy: Always | ||
args: | ||
- "run" | ||
- "--port=9092" | ||
- "--prometheus-label-proxy-endpoint=http://127.0.0.1:9091" | ||
- "--auth-config=/etc/prometheus-auth-config/authn.yaml" | ||
ports: | ||
- name: http | ||
containerPort: 9092 | ||
protocol: TCP | ||
volumeMounts: | ||
- name: prometheus-auth-config | ||
mountPath: /etc/prometheus-auth-config | ||
- name: prometheus-label-proxy | ||
image: angelbarrera92/prom-label-proxy:dev | ||
imagePullPolicy: Always | ||
args: | ||
- "--insecure-listen-address=127.0.0.1:9091" | ||
- "--label=namespace" | ||
- "--upstream=http://prometheus-operated.default.svc.cluster.local:9090" | ||
--- | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: prometheus-multitenant-proxy | ||
namespace: default | ||
labels: | ||
application: prometheus-multitenant-proxy | ||
spec: | ||
type: ClusterIP | ||
ports: | ||
- name: http | ||
port: 9092 | ||
protocol: TCP | ||
targetPort: http | ||
selector: | ||
application: prometheus-multitenant-proxy | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module github.com/angelbarrera92/prometheus-multi-tenant-proxy | ||
|
||
go 1.12 | ||
|
||
require ( | ||
github.com/urfave/cli v1.21.0 | ||
gopkg.in/yaml.v2 v2.2.2 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE= | ||
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package proxy | ||
|
||
import ( | ||
"context" | ||
"crypto/subtle" | ||
"net/http" | ||
|
||
"github.com/angelbarrera92/prometheus-multi-tenant-proxy/internal/pkg" | ||
) | ||
|
||
type key int | ||
|
||
const ( | ||
//Namespace Key used to pass prometheus tenant id though the middleware context | ||
Namespace key = iota | ||
realm = "Prometheus multi-tenant proxy" | ||
) | ||
|
||
// BasicAuth can be used as a middleware chain to authenticate users before proxying a request | ||
func BasicAuth(handler http.HandlerFunc, authConfig *pkg.Authn) http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
user, pass, ok := r.BasicAuth() | ||
authorized, namespace := isAuthorized(user, pass, authConfig) | ||
if !ok || !authorized { | ||
writeUnauthorisedResponse(w) | ||
return | ||
} | ||
ctx := context.WithValue(r.Context(), Namespace, namespace) | ||
handler(w, r.WithContext(ctx)) | ||
} | ||
} | ||
|
||
func isAuthorized(user string, pass string, authConfig *pkg.Authn) (bool, string) { | ||
for _, v := range authConfig.Users { | ||
if subtle.ConstantTimeCompare([]byte(user), []byte(v.Username)) == 1 && subtle.ConstantTimeCompare([]byte(pass), []byte(v.Password)) == 1 { | ||
return true, v.Namespace | ||
} | ||
} | ||
return false, "" | ||
} | ||
|
||
func writeUnauthorisedResponse(w http.ResponseWriter) { | ||
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`) | ||
w.WriteHeader(401) | ||
w.Write([]byte("Unauthorised\n")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package proxy | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/angelbarrera92/prometheus-multi-tenant-proxy/internal/pkg" | ||
) | ||
|
||
func Test_isAuthorized(t *testing.T) { | ||
authConfig := pkg.Authn{ | ||
[]pkg.User{ | ||
pkg.User{ | ||
"User-a", | ||
"pass-a", | ||
"tenant-a", | ||
}, | ||
pkg.User{ | ||
"User-b", | ||
"pass-b", | ||
"tenant-b", | ||
}, | ||
}, | ||
} | ||
type args struct { | ||
user string | ||
pass string | ||
authConfig *pkg.Authn | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want bool | ||
want1 string | ||
}{ | ||
{ | ||
"Valid User", | ||
args{ | ||
"User-a", | ||
"pass-a", | ||
&authConfig, | ||
}, | ||
true, | ||
"tenant-a", | ||
}, { | ||
"Invalid User", | ||
args{ | ||
"invalid", | ||
"pass-a", | ||
&authConfig, | ||
}, | ||
false, | ||
"", | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, got1 := isAuthorized(tt.args.user, tt.args.pass, tt.args.authConfig) | ||
if got != tt.want { | ||
t.Errorf("isAuthorized() got = %v, want %v", got, tt.want) | ||
} | ||
if got1 != tt.want1 { | ||
t.Errorf("isAuthorized() got1 = %v, want %v", got1, tt.want1) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package proxy | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
) | ||
|
||
// LogRequest can be used as a middleware chain to log every request before proxying the request | ||
func LogRequest(handler http.HandlerFunc) http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL) | ||
handler(w, r) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package proxy | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httputil" | ||
"net/url" | ||
"log" | ||
) | ||
|
||
// ReversePrometheus a | ||
func ReversePrometheus(reverseProxy *httputil.ReverseProxy, prometheusLabelProxyServerURL *url.URL) http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
modifyRequest(r, prometheusLabelProxyServerURL) | ||
reverseProxy.ServeHTTP(w, r) | ||
log.Printf("[PROXY]\t%+v\n", r.URL) | ||
} | ||
} | ||
|
||
func modifyRequest(r *http.Request, prometheusLabelProxyServerURL *url.URL) { | ||
r.URL.Scheme = prometheusLabelProxyServerURL.Scheme | ||
r.URL.Host = prometheusLabelProxyServerURL.Host | ||
r.Host = prometheusLabelProxyServerURL.Host | ||
namespace := r.Context().Value(Namespace) | ||
r.Header.Set("X-Forwarded-Host", r.Host) | ||
q := r.URL.Query() | ||
q.Add("namespace", namespace.(string)) | ||
r.URL.RawQuery = q.Encode() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package proxy | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"net/http/httputil" | ||
"net/url" | ||
|
||
"github.com/angelbarrera92/prometheus-multi-tenant-proxy/internal/pkg" | ||
"github.com/urfave/cli" | ||
) | ||
|
||
// Serve serves | ||
func Serve(c *cli.Context) error { | ||
prometheusLabelProxyServerURL, _ := url.Parse(c.String("prometheus-label-proxy-endpoint")) | ||
serveAt := fmt.Sprintf(":%d", c.Int("port")) | ||
authConfigLocation := c.String("auth-config") | ||
authConfig, _ := pkg.ParseConfig(&authConfigLocation) | ||
|
||
http.HandleFunc("/", createHandler(prometheusLabelProxyServerURL, authConfig)) | ||
if err := http.ListenAndServe(serveAt, nil); err != nil { | ||
log.Fatalf("Prometheus multi tenant proxy can not start %v", err) | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func createHandler(prometheusLabelProxyServerURL *url.URL, authConfig *pkg.Authn) http.HandlerFunc { | ||
reverseProxy := httputil.NewSingleHostReverseProxy(prometheusLabelProxyServerURL) | ||
return LogRequest(BasicAuth(ReversePrometheus(reverseProxy, prometheusLabelProxyServerURL), authConfig)) | ||
} |
Oops, something went wrong.