mirror of
https://github.com/netbirdio/netbird-kubeapi-proxy.git
synced 2026-09-23 09:34:58 -07:00
This fixes issues with streaming requests and also makes sure that only specific paths are forwarded to the API server.
147 lines
3.3 KiB
Go
147 lines
3.3 KiB
Go
// SPDX-License-Identifier: AGPL-3.0
|
|
|
|
package proxy
|
|
|
|
import (
|
|
"context"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/go-openapi/testify/v2/require"
|
|
|
|
netbird "github.com/netbirdio/netbird/shared/management/client/rest"
|
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
|
)
|
|
|
|
type mockPeerLister struct{}
|
|
|
|
func (p *mockPeerLister) List(ctx context.Context, opts ...netbird.PeersListOption) ([]api.Peer, error) {
|
|
peers := map[string]api.Peer{
|
|
"192.0.2.1": {
|
|
UserId: "foo",
|
|
Groups: []api.GroupMinimum{
|
|
{
|
|
Name: "group1",
|
|
},
|
|
{
|
|
Name: "group2",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ip := ""
|
|
for _, o := range opts {
|
|
k, v := o()
|
|
if k == "ip" {
|
|
ip = v
|
|
break
|
|
}
|
|
}
|
|
if ip != "" {
|
|
peer, ok := peers[ip]
|
|
if !ok {
|
|
return nil, nil
|
|
}
|
|
return []api.Peer{peer}, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func TestProxyHandler(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
peerStore := NewPeerStore(&mockPeerLister{})
|
|
|
|
bearerToken := "foobar"
|
|
srv := httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
token, _ := strings.CutPrefix(req.Header.Get("Authorization"), "Bearer ")
|
|
if token != bearerToken {
|
|
rw.WriteHeader(http.StatusUnauthorized)
|
|
return
|
|
}
|
|
if req.URL.Path != "/version" {
|
|
rw.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
body := fmt.Sprintf("%s %s %s", req.Header[AuthorizationHeader], req.Header[ImpersonateUserHeader], req.Header[ImpersonateGroupHeader])
|
|
// nolint: errcheck
|
|
rw.Write([]byte(body))
|
|
}))
|
|
t.Cleanup(func() {
|
|
srv.Close()
|
|
})
|
|
certPool := srv.Client().Transport.(*http.Transport).TLSClientConfig.RootCAs
|
|
kubeAPIServerURL, err := url.Parse(srv.URL + "/")
|
|
require.NoError(t, err)
|
|
|
|
tests := []struct {
|
|
name string
|
|
remoteAddr string
|
|
headers map[string]string
|
|
expectedStatus int
|
|
expectedBody string
|
|
}{
|
|
{
|
|
name: "valid peer",
|
|
headers: nil,
|
|
expectedStatus: http.StatusOK,
|
|
expectedBody: "[Bearer foobar] [foo] [group1 group2]",
|
|
},
|
|
{
|
|
name: "valid peer with bearer token",
|
|
headers: map[string]string{
|
|
AuthorizationHeader: "Bearer testtest",
|
|
},
|
|
expectedStatus: http.StatusOK,
|
|
expectedBody: "[Bearer foobar] [foo] [group1 group2]",
|
|
},
|
|
{
|
|
name: "no peer found",
|
|
remoteAddr: "192.0.2.2:123",
|
|
headers: nil,
|
|
expectedStatus: http.StatusUnauthorized,
|
|
expectedBody: "",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
req := httptest.NewRequestWithContext(t.Context(), http.MethodGet, "/version", nil)
|
|
if tt.remoteAddr != "" {
|
|
req.RemoteAddr = tt.remoteAddr
|
|
}
|
|
for k, v := range tt.headers {
|
|
req.Header.Add(k, v)
|
|
}
|
|
rec := httptest.NewRecorder()
|
|
handler := proxyHandler(peerStore, kubeAPIServerURL, certPool, bearerToken)
|
|
handler(rec, req)
|
|
b, err := io.ReadAll(rec.Result().Body)
|
|
require.NoError(t, err)
|
|
|
|
require.EqualT(t, tt.expectedStatus, rec.Result().StatusCode)
|
|
require.EqualT(t, tt.expectedBody, string(b))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenerateSelfSignedCert(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fqdn := "example.com"
|
|
tlsCert, err := generateSelfSignedCert(fqdn)
|
|
require.NoError(t, err)
|
|
x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
|
|
require.NoError(t, err)
|
|
require.Len(t, x509Cert.DNSNames, 1)
|
|
require.EqualT(t, fqdn, x509Cert.DNSNames[0])
|
|
}
|