-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
We add a new API endpoint which proxies GET requests to the K8s api-server. This removes the need to define custom APIs for each use case that requires directly retrieving data from the K8s API. At the moment we can use this API for the web client "Summary" page, which displays information from the AntreaAgentInfo and AntreaControllerInfo CRs. As a result, the specialized "/info" endpoint is now deprecated, and will be removed in the near future (July 2023). The list of API resources being proxied is determined by: 1) a global variable in the backend code; if a client attempts to access an API that is not being proxied, the "Not Found" status code will be returned. Same if the HTTP verb being used is not GET. 2) K8s RBAC permissions for the antrea-ui backend; the list / get verbs must be granted for the resources being proxied. We use the Go standard library reverse proxy implementation. Note that the implementation was greatly improved in Go 1.20, but we currently use Go 1.19 for all Antrea projects. Fixes #10 Signed-off-by: Antonin Bas <abas@vmware.com>
- Loading branch information
1 parent
7b9a831
commit 21c70fc
Showing
11 changed files
with
327 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright 2023 Antrea Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package k8sproxy | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httputil" | ||
"net/url" | ||
|
||
"github.com/go-logr/logr" | ||
) | ||
|
||
type transportWrapper struct { | ||
logger logr.Logger | ||
t http.RoundTripper | ||
} | ||
|
||
func (w *transportWrapper) RoundTrip(r *http.Request) (*http.Response, error) { | ||
w.logger.V(4).Info("Proxying request", "url", r.URL) | ||
return w.t.RoundTrip(r) | ||
} | ||
|
||
func NewK8sProxyHandler(logger logr.Logger, k8sServerURL *url.URL, k8sHTTPTransport http.RoundTripper) http.Handler { | ||
// TODO: the httputil.ReverseProxy is much improved in Go v1.20, but we currently use Go | ||
// v1.19. When we upgrade, we should revisit this code. | ||
k8sReverseProxy := httputil.NewSingleHostReverseProxy(k8sServerURL) | ||
k8sReverseProxy.Transport = &transportWrapper{ | ||
logger: logger, | ||
t: k8sHTTPTransport, | ||
} | ||
return k8sReverseProxy | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright 2023 Antrea Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package k8sproxy | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httptest" | ||
"net/url" | ||
"testing" | ||
|
||
"github.com/go-logr/logr/testr" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestK8sProxyHandler(t *testing.T) { | ||
var capturedReq *http.Request | ||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
capturedReq = r | ||
w.WriteHeader(http.StatusOK) | ||
})) | ||
defer ts.Close() | ||
|
||
logger := testr.New(t) | ||
serverURL, err := url.Parse(ts.URL) | ||
require.NoError(t, err) | ||
h := NewK8sProxyHandler(logger, serverURL, http.DefaultTransport) | ||
|
||
req, err := http.NewRequest("GET", "/api/v1/k8s/api/v1/pods", nil) | ||
req.RemoteAddr = "127.0.0.1:32167" | ||
require.NoError(t, err) | ||
rr := httptest.NewRecorder() | ||
h.ServeHTTP(rr, req) | ||
require.Equal(t, http.StatusOK, rr.Code) | ||
require.NotNil(t, capturedReq) | ||
assert.Equal(t, "GET", capturedReq.Method) | ||
assert.Equal(t, "/api/v1/k8s/api/v1/pods", capturedReq.URL.String()) | ||
// TODO: after we improve the reverse proxy, we need to do more validation | ||
header := capturedReq.Header | ||
assert.Equal(t, "127.0.0.1", header.Get("X-Forwarded-For")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright 2023 Antrea Authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package server | ||
|
||
import ( | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
// allowedPaths contains the K8s api paths that we are proxying. | ||
// Note the leading slash, since the Gin "catch-all" parameter ("/*path") will include it. | ||
var allowedPaths = []string{ | ||
"/apis/crd.antrea.io/v1beta1/antreaagentinfos", | ||
"/apis/crd.antrea.io/v1beta1/antreacontrollerinfos", | ||
} | ||
|
||
func (s *server) GetK8s(c *gin.Context) { | ||
// we need to strip the beginning of the path (/api/v1/k8s) before proxying | ||
path := c.Param("path") | ||
request := c.Request | ||
request.URL.Path = path | ||
// we also ensure that the Bearer Token is removed | ||
request.Header.Del("Authorization") | ||
s.k8sProxyHandler.ServeHTTP(c.Writer, c.Request) | ||
} | ||
|
||
func (s *server) checkK8sPath(c *gin.Context) { | ||
if sError := func() *serverError { | ||
path := c.Param("path") | ||
for _, allowedPath := range allowedPaths { | ||
if strings.HasPrefix(path, allowedPath) { | ||
return nil | ||
} | ||
} | ||
return &serverError{ | ||
code: http.StatusNotFound, | ||
message: "This K8s API path is not being proxied", | ||
} | ||
}(); sError != nil { | ||
s.HandleError(c, sError) | ||
c.Abort() | ||
return | ||
} | ||
} | ||
|
||
func (s *server) AddK8sRoutes(r *gin.RouterGroup) { | ||
r = r.Group("/k8s") | ||
r.Use(s.checkBearerToken) | ||
r.GET("/*path", s.checkK8sPath, s.GetK8s) | ||
} |
Oops, something went wrong.