Grafana接入单点登陆cas实践

Grafana接入单点登陆cas实践

grafana是一款比较流行且好用的可视化制图工具,在实战过程中,往往需要与公司内已有系统做打通,势必带来的问题是如何和内部系统做联动

对grafana添加auth.proxy属性

grafana.ini配置文件中添加如下配置:

[auth.proxy]
	enabled=true
	header_name=X-WEBAUTH-USER
	header_property= username
	auto_sign_up= true

编写grafana-cas,通过golang实现反向代理

package main

import (
	"flag"
	"io"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/go-cas/cas"
	"github.com/go-chi/chi"
	"github.com/golang/glog"
)

var (
	casURL      string
	grafanaAddr string
	serviceAddr string
)

func init() {
	flag.StringVar(&casURL, "cas-url", "sso.example.com", "cas url")
	flag.StringVar(&grafanaAddr, "grafana-addr", "localhost:3000", "grafana addr")
	flag.StringVar(&serviceAddr, "service-addr", ":8080", "grafana proxy addr")
	flag.Parse()
}

func main() {
	url, _ := url.Parse(casURL)
	client := cas.NewClient(&cas.Options{URL: url})
	httpClient = createHTTPClient()
	root := chi.NewRouter()
	root.Use(client.Handler)
	root.HandleFunc("/*", handle)

	server := &http.Server{
		Addr:    serviceAddr,
		Handler: client.Handle(root),
	}
	if err := server.ListenAndServe(); err != nil {
		glog.Fatal(err)
	}
}
var (
	httpClient *http.Client
)

const (
	MaxIdleConnections int = 20
	RequestTimeout int = 30
)

// 重用httpclient
func createHTTPClient() *http.Client {
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: 10 * time.Second,
			}).Dial,
			IdleConnTimeout:     10 * time.Second,
			TLSHandshakeTimeout:   5 * time.Second,
			ResponseHeaderTimeout: 10 * time.Second,
			MaxIdleConns: 50,
			MaxIdleConnsPerHost: MaxIdleConnections,
		},
		Timeout: time.Duration(RequestTimeout) * time.Second,
	}
	return client
}
func handle(w http.ResponseWriter, r *http.Request) {
    // 通过cas登陆的结果获取userName
	user := strings.Split(cas.Username(r), "@")[0]
	r.Header.Add("X-WEBAUTH-USER", user)
	r.Host, r.URL.Host = grafanaAddr, grafanaAddr
	r.RequestURI, r.URL.Scheme = "", "https"
	// 设置连接池
	transport := http.DefaultTransport
	outReq := new(http.Request)
	*outReq = *r 
	res, err := transport.RoundTrip(outReq)
	if err != nil {
		w.WriteHeader(http.StatusBadGateway)
		return
	}

	// 将登陆后的header传递给代理对象
	for key, value := range res.Header {
		for _, v := range value {
			w.Header().Add(key, v)
		}
	}
	w.WriteHeader(res.StatusCode)
	// 将返回结果copy
	io.Copy(w, res.Body)
	res.Body.Close()
}

使用grafana-cas镜像

Dockerfile

FROM golang:1.14.1
ENV GO111MODULE=on \
    GOPROXY=https://goproxy.cn,direct \
    GIN_MODE=release \
    PORT=8080
WORKDIR /app
COPY . /app
RUN go build -o /app/grafana-cas -gcflags "all=-N -l" grafana-cas.go
RUN chmod +x ./grafana-cas
EXPOSE 8080
ENTRYPOINT ["./grafana-cas"]

与k8s做集成

在helm中添加grafanaCas配置

grafanaCas:
	enabled: true
	image:
	  repository: {{imageRepository}}
	  tag: {{imageTag}}
	  pullPolicy: IfNotPresent
	replicas: 1
	service:
	  type: ClusterIP
	  root_url: {{grafana的真实地址}} 
	  port: 80
	  targetPort: 8080
	  annotations: {}
	  labels: {}
	ingress:
	  enabled: true
	  annotations: 
	    kubernetes.io/ingress.class: nginx
	    kubernetes.io/tls-acme: "true"
	  labels: {}
	  path: /
	  hosts:
	    - {{对外提供的grafana的地址}} 
	  tls: 
	  - secretName: {{tls secret}}
	    hosts:
	      - {{对外提供的grafana的地址}} 
	deploymentStrategy:
	  type: RollingUpdate
	  maxSurge: 25%
	  maxUnavailable: 25%
	readinessProbe:
	  httpGet:
	    path: /api/health
	    port: 3000
	  initialDelaySeconds: 20
	  timeoutSeconds: 300
	  failureThreshold: 10

添加deployment,ingress,svc

deployment
{{- if .Values.grafanaCas.enabled -}}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ template "grafanaCas.fullname" . }}
  labels:
    app: {{ template "grafanaCas.name" . }}
    chart: {{ template "grafanaCas.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
spec:
  replicas: {{ .Values.grafanaCas.replicas }}
{{- with .Values.deploymentStrategy }}
  strategy:
{{ toYaml . | trim | indent 4 }}
{{- end }}
  selector:
    matchLabels:
      app: {{ template "grafanaCas.name" . }}
      release: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ template "grafanaCas.name" . }}
        chart: {{ template "grafanaCas.chart" . }}
        release: {{ .Release.Name }}
        heritage: {{ .Release.Service }}
    spec:
      containers:
        - name: {{ template "grafanaCas.name" . }}
          image: "{{ .Values.grafanaCas.image.repository }}:{{ .Values.grafanaCas.image.tag }}"
          imagePullPolicy: {{ .Values.grafanaCas.image.pullPolicy }}
          command: ["./grafana-cas"]
          ports:
            - name: http
              containerPort: {{ .Values.grafanaCas.service.targetPort}}
              protocol: TCP
          livenessProbe:
            tcpSocket:
              port: http
            initialDelaySeconds: 30
            periodSeconds: 20
            timeoutSeconds: 1
          readinessProbe:
            tcpSocket:
              port: http
            initialDelaySeconds: 50
            periodSeconds: 20
            timeoutSeconds: 1
          resources:
            {{- toYaml .Values.grafanaCas.resources | nindent 12 }}
{{- end }}
ingress
{{- if and .Values.grafanaCas.enabled .Values.grafanaCas.ingress.enabled -}}
{{- $fullName := include "grafanaCas.fullname" . -}}
{{- $servicePort := .Values.grafanaCas.service.port -}}
{{- $ingressPath := .Values.grafanaCas.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ $fullName }}
  namespace: {{ .Release.Namespace }}
  labels:
    app: {{ template "grafanaCas.name" . }}
    chart: {{ template "grafanaCas.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
{{- if .Values.grafanaCas.ingress.labels }}
{{ toYaml .Values.grafanaCas.ingress.labels | indent 4 }}
{{- end }}
{{- with .Values.grafanaCas.ingress.annotations }}
  annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.grafanaCas.ingress.tls }}
  tls:
  {{- range .Values.grafanaCas.ingress.tls }}
    - hosts:
      {{- range .hosts }}
        - {{ . | quote }}
      {{- end }}
      secretName: {{ .secretName }}
  {{- end }}
{{- end }}
  rules:
  {{- range .Values.grafanaCas.ingress.hosts }}
    - host: {{ . }}
      http:
        paths:
          - path: {{ $ingressPath }}
            backend:
              serviceName: {{ $fullName }}
              servicePort: {{ $servicePort }}
  {{- end }}
{{- end }}
svc
{{- if .Values.grafanaCas.enabled -}}
apiVersion: v1
kind: Service
metadata:
  name: {{ template "grafanaCas.fullname" . }}
  namespace: {{ .Release.Namespace }}
  labels:
    app: {{ template "grafanaCas.name" . }}
    chart: {{ template "grafanaCas.chart" . }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
{{- if .Values.grafanaCas.service.labels }}
{{ toYaml .Values.grafanaCas.service.labels | indent 4 }}
{{- end }}
{{- with .Values.grafanaCas.service.annotations }}
  annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if (or (eq .Values.grafanaCas.service.type "ClusterIP") (empty .Values.grafanaCas.service.type)) }}
  type: ClusterIP
  {{- if .Values.grafanaCas.service.clusterIP }}
  clusterIP: {{ .Values.grafanaCas.service.clusterIP }}
  {{end}}
{{- else if eq .Values.grafanaCas.service.type "LoadBalancer" }}
  type: {{ .Values.grafanaCas.service.type }}
  {{- if .Values.grafanaCas.service.loadBalancerIP }}
  loadBalancerIP: {{ .Values.grafanaCas.service.loadBalancerIP }}
  {{- end }}
  {{- if .Values.grafanaCas.service.loadBalancerSourceRanges }}
  loadBalancerSourceRanges:
{{ toYaml .Values.grafanaCas.service.loadBalancerSourceRanges | indent 4 }}
  {{- end -}}
{{- else }}
  type: {{ .Values.grafanaCas.service.type }}
{{- end }}
{{- if .Values.grafanaCas.service.externalIPs }}
  externalIPs:
{{ toYaml .Values.grafanaCas.service.externalIPs | indent 4 }}
{{- end }}
  ports:
    - name: service
      port: {{ .Values.grafanaCas.service.port }}
      protocol: TCP
      targetPort: {{ .Values.grafanaCas.service.targetPort }}
{{ if (and (eq .Values.grafanaCas.service.type "NodePort") (not (empty .Values.grafanaCas.service.nodePort))) }}
      nodePort: {{.Values.grafanaCas.service.nodePort}}
{{ end }}
  selector:
    app: {{ template "grafanaCas.name" . }}
    release: {{ .Release.Name }}
{{- end }}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值