fix: 代理 Runner 仓库 HTTP 流量
This commit is contained in:
@@ -126,7 +126,7 @@ func runController(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
facadeServer := runnerfacade.Server{
|
facadeServer := runnerfacade.Server{
|
||||||
Facade: facade, ListenAddress: config.FacadeListen, TrustDomain: config.TrustDomain,
|
Facade: facade, ListenAddress: config.FacadeListen, TrustDomain: config.TrustDomain,
|
||||||
WorkloadAPIAddr: config.WorkloadAPIAddr,
|
WorkloadAPIAddr: config.WorkloadAPIAddr, UpstreamURL: config.GiteaURL,
|
||||||
}
|
}
|
||||||
components := controller.Registry{
|
components := controller.Registry{
|
||||||
controller.Scheduler: runComponent(func(ctx context.Context) error {
|
controller.Scheduler: runComponent(func(ctx context.Context) error {
|
||||||
|
|||||||
@@ -130,6 +130,31 @@ func TestAPIHandlerMatchesOfficialRunnerBasePath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHandlerProxiesRepositoryTrafficToGitea(t *testing.T) {
|
||||||
|
upstream := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if request.URL.Path != "/owner/repo/info/refs" || request.Header.Get("Authorization") != "Basic checkout-token" {
|
||||||
|
t.Errorf("request path=%q authorization=%q", request.URL.Path, request.Header.Get("Authorization"))
|
||||||
|
response.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
defer upstream.Close()
|
||||||
|
|
||||||
|
facade, _, _ := testFacade(t)
|
||||||
|
handler, err := Handler(facade, upstream.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
request := httptest.NewRequest(http.MethodGet, "http://facade/owner/repo/info/refs", nil)
|
||||||
|
request.Header.Set("Authorization", "Basic checkout-token")
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(response, request)
|
||||||
|
if response.Code != http.StatusOK {
|
||||||
|
t.Fatalf("status = %d", response.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFacadeRejectsWrongIdentityOrCapability(t *testing.T) {
|
func TestFacadeRejectsWrongIdentityOrCapability(t *testing.T) {
|
||||||
facade, assignment, token := testFacade(t)
|
facade, assignment, token := testFacade(t)
|
||||||
wrongIdentity := WithSPIFFEID(context.Background(), "spiffe://ddupan.top/ci/owner/repo/other")
|
wrongIdentity := WithSPIFFEID(context.Background(), "spiffe://ddupan.top/ci/owner/repo/other")
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
"github.com/spiffe/go-spiffe/v2/spiffeid"
|
||||||
@@ -25,19 +27,40 @@ func APIHandler(facade *Facade) http.Handler {
|
|||||||
return mux
|
return mux
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handler keeps RunnerService calls inside the authenticated facade while
|
||||||
|
// forwarding repository and artifact HTTP traffic to the real Gitea server.
|
||||||
|
// Official Runner derives checkout URLs from its registration instance URL,
|
||||||
|
// which intentionally points at the executor-local SPIFFE proxy.
|
||||||
|
func Handler(facade *Facade, upstreamURL string) (http.Handler, error) {
|
||||||
|
target, err := url.Parse(upstreamURL)
|
||||||
|
if err != nil || (target.Scheme != "http" && target.Scheme != "https") || target.Host == "" {
|
||||||
|
return nil, errors.New("Gitea upstream must be an absolute HTTP URL")
|
||||||
|
}
|
||||||
|
path, service := facade.Handler()
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.Handle(APIBasePath+path, http.StripPrefix(APIBasePath, SPIFFEMiddleware(service)))
|
||||||
|
mux.Handle("/", httputil.NewSingleHostReverseProxy(target))
|
||||||
|
return mux, nil
|
||||||
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Facade *Facade
|
Facade *Facade
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
TrustDomain string
|
TrustDomain string
|
||||||
WorkloadAPIAddr string
|
WorkloadAPIAddr string
|
||||||
|
UpstreamURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run serves the RunnerService facade with workload-to-workload mTLS. Any
|
// Run serves the RunnerService facade with workload-to-workload mTLS. Any
|
||||||
// identity in the local trust domain may complete TLS; the facade then requires
|
// identity in the local trust domain may complete TLS; the facade then requires
|
||||||
// the exact logical task identity stored in its assignment registry.
|
// the exact logical task identity stored in its assignment registry.
|
||||||
func (s Server) Run(ctx context.Context) error {
|
func (s Server) Run(ctx context.Context) error {
|
||||||
if s.Facade == nil || s.ListenAddress == "" || s.TrustDomain == "" {
|
if s.Facade == nil || s.ListenAddress == "" || s.TrustDomain == "" || s.UpstreamURL == "" {
|
||||||
return errors.New("runner facade, listen address, and trust domain are required")
|
return errors.New("runner facade, listen address, trust domain, and Gitea upstream are required")
|
||||||
|
}
|
||||||
|
handler, err := Handler(s.Facade, s.UpstreamURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
trustDomain, err := spiffeid.TrustDomainFromString(s.TrustDomain)
|
trustDomain, err := spiffeid.TrustDomainFromString(s.TrustDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -61,7 +84,7 @@ func (s Server) Run(ctx context.Context) error {
|
|||||||
tlsListener := tls.NewListener(listener, tlsconfig.MTLSServerConfig(
|
tlsListener := tls.NewListener(listener, tlsconfig.MTLSServerConfig(
|
||||||
source, source, tlsconfig.AuthorizeMemberOf(trustDomain),
|
source, source, tlsconfig.AuthorizeMemberOf(trustDomain),
|
||||||
))
|
))
|
||||||
httpServer := &http.Server{Handler: APIHandler(s.Facade), ReadHeaderTimeout: 10 * time.Second}
|
httpServer := &http.Server{Handler: handler, ReadHeaderTimeout: 10 * time.Second}
|
||||||
serverErrors := make(chan error, 1)
|
serverErrors := make(chan error, 1)
|
||||||
go func() { serverErrors <- httpServer.Serve(tlsListener) }()
|
go func() { serverErrors <- httpServer.Serve(tlsListener) }()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user