Skip to content

Instantly share code, notes, and snippets.

@iwanhae
Created November 5, 2023 06:51
Show Gist options
  • Save iwanhae/b4df2d332c505170b35f024d94f4c461 to your computer and use it in GitHub Desktop.
Save iwanhae/b4df2d332c505170b35f024d94f4c461 to your computer and use it in GitHub Desktop.
Kubernetes API Audit PoC
package main
import (
"compress/gzip"
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"log"
"net/http"
"net/http/httputil"
"os"
"strings"
"sync"
"sync/atomic"
)
var key = &struct{}{}
func main() {
mu := &sync.Mutex{}
proxy := httputil.ReverseProxy{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
Rewrite: func(r *httputil.ProxyRequest) {
req := r.In
// Print Request
mu.Lock()
defer mu.Unlock()
fmt.Println("--------", req.Method, req.URL)
r.Out.URL.Host = "YOUR_HOST_HERE:6443"
r.Out.URL.Scheme = "https"
r.Out.Header.Set("X-Forwarded-For", req.RemoteAddr)
r.Out.Header.Set("X-Forwarded-Host", req.Host)
r.Out.Header.Set("X-Forwarded-Proto", "http")
r.Out.Header.Set("Authorization", "Bearer YOURSECRETHERE")
f := r.In.Context().Value(key).(*os.File)
fmt.Fprintf(f, "%s %s %s\n", req.Method, req.URL, req.Proto)
for k, v := range req.Header {
fmt.Fprintf(f, "%s: %s\n", k, strings.Join(v, ","))
}
fmt.Fprintf(f, "\n")
r.In.Body = TeeReadCloser(r.In.Body, f)
},
ModifyResponse: func(r *http.Response) error {
f := r.Request.Context().Value(key).(*os.File)
fmt.Fprintf(f, "===\n")
fmt.Fprintf(f, "%s\n", r.Status)
for k, v := range r.Header {
fmt.Fprintf(f, "%s: %s\n", k, strings.Join(v, ","))
}
fmt.Fprintf(f, "\n")
r.Body = TeeReadCloser(r.Body, f)
return nil
},
}
// Start the proxy server
log.Fatal(http.ListenAndServe(":8000", &FileOpenMW{&proxy, atomic.Int32{}}))
}
type Decompressor struct {
io.WriteCloser
*io.PipeReader
*io.PipeWriter
*gzip.Reader
}
type FileOpenMW struct {
http.Handler
counter atomic.Int32
}
func (t *FileOpenMW) ServeHTTP(w http.ResponseWriter, r *http.Request) {
t.counter.Add(1)
f, err := os.OpenFile(fmt.Sprintf("audit/%v.http", t.counter.Load()), os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
r = r.WithContext(context.WithValue(r.Context(), key, f))
t.Handler.ServeHTTP(w, r)
}
type teeReadCloser struct {
r io.ReadCloser
rWraiteable io.Writer
w io.WriteCloser
}
func TeeReadCloser(r io.ReadCloser, w io.WriteCloser) io.ReadCloser {
var rWraiteable io.Writer = nil
if rw, ok := r.(io.Writer); ok {
rWraiteable = rw
}
return &teeReadCloser{
r: r,
rWraiteable: rWraiteable,
w: w,
}
}
// Write implements io.ReadWriteCloser.
func (t *teeReadCloser) Write(p []byte) (n int, err error) {
return t.rWraiteable.Write(p)
}
func (t *teeReadCloser) Close() error {
return errors.Join(t.w.Close(), t.r.Close())
}
func (t *teeReadCloser) Read(p []byte) (n int, err error) {
n, err = t.r.Read(p)
if n > 0 {
if n, err := t.w.Write(p[:n]); err != nil {
return n, err
}
}
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment