130 lines
2.8 KiB
Go
130 lines
2.8 KiB
Go
package auditing
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"k8s.io/klog"
|
|
"kubesphere.io/kubesphere/pkg/apiserver/auditing/v1alpha1"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
WaitTimeout = time.Second
|
|
WebhookURL = "https://kube-auditing-webhook-svc.kubesphere-logging-system.svc:443/audit/webhook/event"
|
|
)
|
|
|
|
type Backend struct {
|
|
url string
|
|
channelCapacity int
|
|
semCh chan interface{}
|
|
cache chan *v1alpha1.EventList
|
|
client http.Client
|
|
sendTimeout time.Duration
|
|
waitTimeout time.Duration
|
|
stopCh <-chan struct{}
|
|
}
|
|
|
|
func NewBackend(url string, channelCapacity int, cache chan *v1alpha1.EventList, sendTimeout time.Duration, stopCh <-chan struct{}) *Backend {
|
|
|
|
b := Backend{
|
|
url: url,
|
|
semCh: make(chan interface{}, channelCapacity),
|
|
channelCapacity: channelCapacity,
|
|
waitTimeout: WaitTimeout,
|
|
cache: cache,
|
|
sendTimeout: sendTimeout,
|
|
stopCh: stopCh,
|
|
}
|
|
|
|
if len(b.url) == 0 {
|
|
b.url = WebhookURL
|
|
}
|
|
|
|
b.client = http.Client{
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
},
|
|
},
|
|
Timeout: b.sendTimeout,
|
|
}
|
|
|
|
go b.worker()
|
|
|
|
return &b
|
|
}
|
|
|
|
func (b *Backend) worker() {
|
|
|
|
for {
|
|
|
|
var event *v1alpha1.EventList
|
|
select {
|
|
case event = <-b.cache:
|
|
if event == nil {
|
|
break
|
|
}
|
|
case <-b.stopCh:
|
|
break
|
|
}
|
|
|
|
send := func(event *v1alpha1.EventList) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), b.waitTimeout)
|
|
defer cancel()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
klog.Errorf("get goroutine for audit(%s) timeout", event.Items[0].AuditID)
|
|
return
|
|
case b.semCh <- struct{}{}:
|
|
}
|
|
|
|
defer func() {
|
|
<-b.semCh
|
|
}()
|
|
|
|
bs, err := b.eventToBytes(event)
|
|
if err != nil {
|
|
klog.V(6).Infof("json marshal error, %s", err)
|
|
return
|
|
}
|
|
|
|
klog.V(8).Infof("%s", string(bs))
|
|
|
|
response, err := b.client.Post(b.url, "application/json", bytes.NewBuffer(bs))
|
|
if err != nil {
|
|
klog.Errorf("send audit event[%s] error, %s", event.Items[0].AuditID, err)
|
|
return
|
|
}
|
|
|
|
if response.StatusCode != http.StatusOK {
|
|
klog.Errorf("send audit event[%s] error[%d]", event.Items[0].AuditID, response.StatusCode)
|
|
return
|
|
}
|
|
}
|
|
|
|
go send(event)
|
|
}
|
|
}
|
|
|
|
func (b *Backend) eventToBytes(event *v1alpha1.EventList) ([]byte, error) {
|
|
|
|
bs, err := json.Marshal(event)
|
|
if err != nil {
|
|
// Normally, the serialization failure is caused by the failure of ResponseObject serialization.
|
|
// To ensure the integrity of the auditing event to the greatest extent,
|
|
// it is necessary to delete ResponseObject and and then try to serialize again.
|
|
if event.Items[0].ResponseObject != nil {
|
|
event.Items[0].ResponseObject = nil
|
|
return json.Marshal(event)
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
return bs, err
|
|
}
|