mirror of
https://github.com/netbirdio/netbird-kubeapi-proxy.git
synced 2026-09-23 09:34:58 -07:00
Add initial API server proxy
Co-authored-by: Shyam <shyam0904a@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
**
|
||||
!bin/*/netbird-kubeapi-proxy
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
bin/*
|
||||
Dockerfile.cross
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
# Kubernetes Generated files - skip generated files, except for vendored files
|
||||
!vendor/**/zz_generated.*
|
||||
|
||||
# editor and IDE paraphernalia
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
@@ -0,0 +1,61 @@
|
||||
version: "2"
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- copyloopvar
|
||||
- dupl
|
||||
- errcheck
|
||||
- ginkgolinter
|
||||
- gocyclo
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- nakedret
|
||||
- prealloc
|
||||
- revive
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- importas
|
||||
- goheader
|
||||
settings:
|
||||
revive:
|
||||
rules:
|
||||
- name: comment-spacings
|
||||
staticcheck:
|
||||
checks: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022", "-QF1008", "-SA1019"]
|
||||
importas:
|
||||
alias:
|
||||
- pkg: github.com/netbirdio/netbird/shared/management/client/rest
|
||||
alias: netbird
|
||||
no-extra-aliases: true
|
||||
goheader:
|
||||
template: |-
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
exclusions:
|
||||
generated: lax
|
||||
rules:
|
||||
- linters:
|
||||
- dupl
|
||||
path: internal/*
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
enable:
|
||||
- gci
|
||||
- gofmt
|
||||
settings:
|
||||
gci:
|
||||
sections:
|
||||
- blank
|
||||
- standard
|
||||
- prefix(golang.org/x)
|
||||
- default
|
||||
- prefix(github.com/netbirdio)
|
||||
- localmodule
|
||||
no-inline-comments: true
|
||||
no-prefix-comments: true
|
||||
custom-order: true
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
FROM gcr.io/distroless/static:nonroot
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
LABEL org.opencontainers.image.title="NetBird Kubernetes API Proxy" \
|
||||
org.opencontainers.image.description="Authorization proxy of Kubernetes API server using NetBird connections as identities." \
|
||||
org.opencontainers.image.source="https://github.com/netbirdio/netbird-kubeapi-proxy" \
|
||||
org.opencontainers.image.vendor="NetBird" \
|
||||
org.opencontainers.image.licenses="BSD-3-Clause"
|
||||
COPY bin/${TARGETOS}-${TARGETARCH}/netbird-kubeapi-proxy /usr/local/bin/
|
||||
USER 65532:65532
|
||||
ENTRYPOINT ["netbird-kubeapi-proxy"]
|
||||
@@ -0,0 +1,29 @@
|
||||
IMG_REGISTRY ?= ghcr.io
|
||||
IMG_REPOSITORY ?= netbirdio/netbird-kubeapi-proxy
|
||||
IMG_TAG ?= dev
|
||||
IMG_REF := $(IMG_REGISTRY)/$(IMG_REPOSITORY):$(IMG_TAG)
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@golangci-lint run ./...
|
||||
|
||||
.PHONY: build
|
||||
build: bin/linux-$(shell go env GOARCH)/netbird-kubeapi-proxy
|
||||
|
||||
bin/linux-%/netbird-kubeapi-proxy: $(shell find internal) main.go go.mod go.sum
|
||||
@CGO_ENABLED=0 GOOS=linux GOARCH=$* go build -ldflags="-w -s" -trimpath -o $@ main.go
|
||||
|
||||
.PHONY: build-image
|
||||
build-image: build
|
||||
@DOCKER_BUILDKIT=1 docker build -t ${IMG_REF} .
|
||||
@echo ${IMG_REF}
|
||||
|
||||
.PHONY: build-image-multiarch
|
||||
build-image-multiarch: bin/linux-amd64/netbird-kubeapi-proxy bin/linux-arm64/netbird-kubeapi-proxy
|
||||
@DOCKER_BUILDKIT=1 docker build --platform linux/amd64,linux/arm64 -t ${IMG_REF} .
|
||||
@echo ${IMG_REF}
|
||||
|
||||
deploy: build-image
|
||||
kind load docker-image ${IMG_REF}
|
||||
kustomize build manifests | kubectl apply -f -
|
||||
kubectl rollout restart deployment/netbird-kubeapi-proxy
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: cluster-reader
|
||||
rules:
|
||||
- apiGroups: ["*"]
|
||||
resources: ["*"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: kubernetes-reader-binding
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: kubernetes-read
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-reader
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
@@ -0,0 +1,135 @@
|
||||
module github.com/netbirdio/netbird-kubeapi-proxy
|
||||
|
||||
go 1.25.5
|
||||
|
||||
toolchain go1.26.3
|
||||
|
||||
require (
|
||||
github.com/netbirdio/netbird v0.71.2
|
||||
golang.org/x/sync v0.20.0
|
||||
)
|
||||
|
||||
require (
|
||||
cunicu.li/go-rosenpass v0.4.0 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.38.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.31.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.18.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.42.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.29.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.38.2 // indirect
|
||||
github.com/aws/smithy-go v1.23.0 // indirect
|
||||
github.com/caddyserver/certmagic v0.21.3 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cilium/ebpf v0.15.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.3 // indirect
|
||||
github.com/coder/websocket v1.8.14 // indirect
|
||||
github.com/coreos/go-iptables v0.7.0 // indirect
|
||||
github.com/creack/pty v1.1.24 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/gliderlabs/ssh v0.3.8 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/nftables v0.3.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gopacket/gopacket v1.1.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/huin/goupnp v1.2.0 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/libdns/libdns v0.2.2 // indirect
|
||||
github.com/libdns/route53 v1.5.0 // indirect
|
||||
github.com/libp2p/go-nat v0.2.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.4.0 // indirect
|
||||
github.com/lrh3321/ipset-go v0.0.0-20250619021614-54a0a98ace81 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
|
||||
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/mholt/acmez/v2 v2.0.1 // indirect
|
||||
github.com/miekg/dns v1.1.72 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/oapi-codegen/runtime v1.1.2 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20250303134427-723919f7f203 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.10 // indirect
|
||||
github.com/pion/dtls/v3 v3.0.9 // indirect
|
||||
github.com/pion/ice/v4 v4.0.0-00010101000000-000000000000 // indirect
|
||||
github.com/pion/logging v0.2.4 // indirect
|
||||
github.com/pion/mdns/v2 v2.0.7 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/stun/v2 v2.0.0 // indirect
|
||||
github.com/pion/stun/v3 v3.1.0 // indirect
|
||||
github.com/pion/transport/v2 v2.2.4 // indirect
|
||||
github.com/pion/transport/v3 v3.1.1 // indirect
|
||||
github.com/pion/turn/v3 v3.0.1 // indirect
|
||||
github.com/pion/turn/v4 v4.1.1 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/sftp v1.13.9 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/quic-go/quic-go v0.55.0 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.2.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/things-go/go-socks5 v0.0.4 // indirect
|
||||
github.com/ti-mo/conntrack v0.5.1 // indirect
|
||||
github.com/ti-mo/netfilter v0.5.2 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/vishvananda/netlink v1.3.1 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
github.com/zcalusic/sysinfo v1.1.3 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.50.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/mod v0.34.0 // indirect
|
||||
golang.org/x/net v0.53.0 // indirect
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
golang.org/x/tools v0.43.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 // indirect
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
|
||||
google.golang.org/grpc v1.80.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20260219192049-0f2374377e89 // indirect
|
||||
)
|
||||
|
||||
replace github.com/dexidp/dex => github.com/netbirdio/dex v0.244.1-0.20260512110716-8d70ad8647c1
|
||||
|
||||
replace github.com/cloudflare/circl => codeberg.org/cunicu/circl v0.0.0-20230801113412-fec58fc7b5f6
|
||||
|
||||
replace github.com/pion/ice/v4 => github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51
|
||||
|
||||
replace golang.zx2c4.com/wireguard => github.com/netbirdio/wireguard-go v0.0.0-20260107100953-33b7c9d03db0
|
||||
|
||||
replace github.com/netbirdio/netbird => github.com/netbirdio/netbird v0.71.5-0.20260525190024-d542c60e2182
|
||||
@@ -0,0 +1,139 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/client/embed"
|
||||
netbird "github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
)
|
||||
|
||||
func Server(embedClient *embed.Client, netbirdClient *netbird.Client, kubeAPIServerURL *url.URL) (*http.Server, error) {
|
||||
saToken, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bearerToken := string(saToken)
|
||||
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k8sCA, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok := certPool.AppendCertsFromPEM(k8sCA); !ok {
|
||||
return nil, fmt.Errorf("failed to append Kubernetes CA certificate")
|
||||
}
|
||||
|
||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
transport.TLSClientConfig = &tls.Config{
|
||||
RootCAs: certPool,
|
||||
}
|
||||
proxy := &httputil.ReverseProxy{
|
||||
Transport: transport,
|
||||
Rewrite: func(pr *httputil.ProxyRequest) {
|
||||
allowedHeaders := map[string]any{
|
||||
"Accept": nil,
|
||||
"Accept-Encoding": nil,
|
||||
"Content-Length": nil,
|
||||
"Content-Type": nil,
|
||||
"User-Agent": nil,
|
||||
}
|
||||
for k := range pr.Out.Header {
|
||||
if _, ok := allowedHeaders[k]; !ok {
|
||||
pr.Out.Header.Del(k)
|
||||
}
|
||||
}
|
||||
|
||||
remoteIP, _, err := net.SplitHostPort(pr.In.RemoteAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
listCtx, listCancel := context.WithTimeout(pr.In.Context(), 10*time.Second)
|
||||
defer listCancel()
|
||||
peers, err := netbirdClient.Peers.List(listCtx, netbird.PeerIPFilter(remoteIP))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(peers) != 1 {
|
||||
return
|
||||
}
|
||||
peer := peers[0]
|
||||
pr.Out.Header.Set("Impersonate-User", peer.UserId)
|
||||
for _, group := range peer.Groups {
|
||||
pr.Out.Header.Add("Impersonate-Group", group.Name)
|
||||
}
|
||||
|
||||
pr.Out.Header.Set("Authorization", "Bearer "+bearerToken)
|
||||
pr.SetURL(kubeAPIServerURL)
|
||||
},
|
||||
}
|
||||
|
||||
stat, err := embedClient.Status()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proxyCert, err := generateSelfSignedCert(stat.LocalPeerState.FQDN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
srv := http.Server{
|
||||
TLSConfig: &tls.Config{
|
||||
Certificates: []tls.Certificate{proxyCert},
|
||||
MinVersion: tls.VersionTLS12,
|
||||
},
|
||||
Handler: proxy,
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
}
|
||||
return &srv, nil
|
||||
}
|
||||
|
||||
func generateSelfSignedCert(fqdn string) (tls.Certificate, error) {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
template := x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"NetBird K8s Auth Proxy"},
|
||||
CommonName: fqdn,
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(365 * 24 * time.Hour),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
DNSNames: []string{fqdn},
|
||||
}
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
return tls.Certificate{
|
||||
Certificate: [][]byte{certDER},
|
||||
PrivateKey: priv,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/netbirdio/netbird/client/embed"
|
||||
netbird "github.com/netbirdio/netbird/shared/management/client/rest"
|
||||
|
||||
"github.com/netbirdio/netbird-kubeapi-proxy/internal/proxy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
mgmtURL string
|
||||
apiKey string
|
||||
setupKey string
|
||||
kubeAPIServer string
|
||||
instanceName string
|
||||
clusterName string
|
||||
)
|
||||
flag.StringVar(&mgmtURL, "management-url", "https://api.netbird.io", "NetBird management URL")
|
||||
flag.StringVar(&apiKey, "api-key", os.Getenv("NB_API_KEY"), "NetBird API key")
|
||||
flag.StringVar(&setupKey, "setup-key", os.Getenv("NB_SETUP_KEY"), "NetBird setup key")
|
||||
flag.StringVar(&kubeAPIServer, "kubernetes-api-server", "https://kubernetes.default.svc.cluster.local", "Target Kubernetes API server URL")
|
||||
flag.StringVar(&instanceName, "instance-name", "", "Name of the instance")
|
||||
flag.StringVar(&clusterName, "cluster-name", "", "Name of the cluster")
|
||||
flag.Parse()
|
||||
|
||||
err := run(context.Background(), kubeAPIServer, mgmtURL, apiKey, setupKey, instanceName, clusterName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run(ctx context.Context, kubeAPIServer, mgmtURL, apiKey, setupKey, instanceName, clusterName string) error {
|
||||
ctx, cancel := signal.NotifyContext(ctx, syscall.SIGTERM)
|
||||
defer cancel()
|
||||
g, gCtx := errgroup.WithContext(ctx)
|
||||
|
||||
kubeAPIServerURL, err := url.Parse(kubeAPIServer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if kubeAPIServerURL.Scheme != "https" || kubeAPIServerURL.Host == "" {
|
||||
return errors.New("kubernetes-api-server must be an absolute https URL")
|
||||
}
|
||||
|
||||
netbirdClient := netbird.NewWithOptions(
|
||||
netbird.WithManagementURL(mgmtURL),
|
||||
netbird.WithBearerToken(apiKey),
|
||||
)
|
||||
|
||||
opts := embed.Options{
|
||||
ManagementURL: mgmtURL,
|
||||
SetupKey: setupKey,
|
||||
DeviceName: instanceName,
|
||||
LogOutput: io.Discard,
|
||||
DNSLabels: []string{clusterName + "." + "netbird-kubeapi-proxy"},
|
||||
}
|
||||
embedClient, err := embed.New(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = embedClient.Start(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.Go(func() error {
|
||||
<-gCtx.Done()
|
||||
return embedClient.Stop(context.Background())
|
||||
})
|
||||
|
||||
proxySrv, err := proxy.Server(embedClient, netbirdClient, kubeAPIServerURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listener, err := embedClient.ListenTCP(":443")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.Go(func() error {
|
||||
err := proxySrv.ServeTLS(listener, "", "")
|
||||
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
g.Go(func() error {
|
||||
<-gCtx.Done()
|
||||
return proxySrv.Shutdown(context.Background())
|
||||
})
|
||||
|
||||
err = g.Wait()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: netbird-kubeapi-proxy
|
||||
labels:
|
||||
app.kubernetes.io/name: netbird-kubeapi-proxy
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: netbird-kubeapi-proxy
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: netbird-kubeapi-proxy
|
||||
spec:
|
||||
serviceAccountName: netbird-kubeapi-proxy
|
||||
securityContext:
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: proxy
|
||||
image: ghcr.io/netbirdio/netbird-kubeapi-proxy:dev
|
||||
args:
|
||||
- --api-key=$(API_KEY)
|
||||
- --setup-key=$(SETUP_KEY)
|
||||
- --instance-name=$(POD_NAME)
|
||||
- --cluster-name=kubernetes
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: SETUP_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: netbird-kubeapi-proxy
|
||||
key: setup-key
|
||||
- name: API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: netbird-kubeapi-proxy
|
||||
key: api-key
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
@@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- deployment.yaml
|
||||
- rbac.yaml
|
||||
@@ -0,0 +1,38 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: netbird-kubeapi-proxy
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: netbird-kubeapi-proxy
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- users
|
||||
- groups
|
||||
verbs:
|
||||
- impersonate
|
||||
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- userextras/*
|
||||
- uids
|
||||
verbs:
|
||||
- impersonate
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: netbird-kubeapi-proxy
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: netbird-kubeapi-proxy
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: netbird-kubeapi-proxy
|
||||
namespace: default
|
||||
Reference in New Issue
Block a user