Skip to content

Commit 75902a6

Browse files
Merge pull request #13321 from stlaz/selfinfo
CONSOLE-3829, OCPBUGS-16814: backend: use the k8s SelfSubjectReview API to get info about a user
2 parents 8bde63c + e87dc6f commit 75902a6

97 files changed

Lines changed: 18572 additions & 735 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/bridge/config/auth/authoptions.go

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"flag"
66
"fmt"
7-
"net/http"
87
"net/url"
98
"os"
109

@@ -194,7 +193,6 @@ func (c *AuthOptions) Validate(k8sAuthType string) []error {
194193
func (c *completedOptions) ApplyTo(
195194
srv *server.Server,
196195
k8sEndpoint *url.URL,
197-
pubAPIServerEndpoint string,
198196
caCertFilePath string,
199197
) error {
200198
srv.InactivityTimeout = c.InactivityTimeoutSeconds
@@ -204,9 +202,8 @@ func (c *completedOptions) ApplyTo(
204202
srv.Authenticator, err = c.getAuthenticator(
205203
srv.BaseURL,
206204
k8sEndpoint,
207-
pubAPIServerEndpoint,
208205
caCertFilePath,
209-
srv.K8sClient.Transport,
206+
srv.InternalProxiedK8SClientConfig,
210207
)
211208

212209
return err
@@ -215,9 +212,8 @@ func (c *completedOptions) ApplyTo(
215212
func (c *completedOptions) getAuthenticator(
216213
baseURL *url.URL,
217214
k8sEndpoint *url.URL,
218-
pubAPIServerEndpoint string,
219215
caCertFilePath string,
220-
k8sTransport http.RoundTripper,
216+
k8sClientConfig *rest.Config,
221217
) (*auth.Authenticator, error) {
222218

223219
if c.AuthType == "disabled" {
@@ -276,10 +272,7 @@ func (c *completedOptions) getAuthenticator(
276272
RefererPath: refererPath,
277273
SecureCookies: useSecureCookies,
278274

279-
K8sConfig: &rest.Config{
280-
Host: pubAPIServerEndpoint,
281-
Transport: k8sTransport,
282-
},
275+
K8sConfig: k8sClientConfig,
283276
}
284277

285278
authenticator, err := auth.NewAuthenticator(context.Background(), oidcClientConfig)

cmd/bridge/main.go

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/openshift/console/pkg/serverconfig"
2323
oscrypto "github.com/openshift/library-go/pkg/crypto"
2424

25+
"k8s.io/client-go/rest"
2526
"k8s.io/klog"
2627
)
2728

@@ -322,6 +323,13 @@ func main() {
322323
klog.Fatalf("failed to read bearer token: %v", err)
323324
}
324325

326+
srv.InternalProxiedK8SClientConfig = &rest.Config{
327+
Host: k8sEndpoint.String(),
328+
TLSClientConfig: rest.TLSClientConfig{
329+
CAFile: k8sInClusterCA,
330+
},
331+
}
332+
325333
srv.K8sProxyConfig = &proxy.Config{
326334
TLSClientConfig: tlsConfig,
327335
HeaderBlacklist: []string{"Cookie", "X-CSRFToken"},
@@ -405,6 +413,11 @@ func main() {
405413
},
406414
}
407415

416+
srv.InternalProxiedK8SClientConfig = &rest.Config{
417+
Host: k8sEndpoint.String(),
418+
Transport: &http.Transport{TLSClientConfig: serviceProxyTLSConfig},
419+
}
420+
408421
srv.K8sProxyConfig = &proxy.Config{
409422
TLSClientConfig: serviceProxyTLSConfig,
410423
HeaderBlacklist: []string{"Cookie", "X-CSRFToken"},
@@ -478,11 +491,6 @@ func main() {
478491
apiServerEndpoint = srv.K8sProxyConfig.Endpoint.String()
479492
}
480493
srv.KubeAPIServerURL = apiServerEndpoint
481-
srv.K8sClient = &http.Client{
482-
Transport: &http.Transport{
483-
TLSClientConfig: srv.K8sProxyConfig.TLSClientConfig,
484-
},
485-
}
486494

487495
clusterManagementURL, err := url.Parse(clusterManagementURL)
488496
if err != nil {
@@ -498,31 +506,28 @@ func main() {
498506
case "service-account":
499507
flags.FatalIfFailed(flags.ValidateFlagIs("k8s-mode", *fK8sMode, "in-cluster"))
500508
srv.StaticUser = &auth.User{
501-
Token: k8sAuthServiceAccountBearerToken,
509+
Token: k8sAuthServiceAccountBearerToken, // FIXME: make it read the token from the file and periodically re-read?
502510
}
503-
srv.ServiceAccountToken = k8sAuthServiceAccountBearerToken
511+
srv.InternalProxiedK8SClientConfig.BearerTokenFile = k8sInClusterBearerToken
504512
case "bearer-token":
505513
flags.FatalIfFailed(flags.ValidateFlagNotEmpty("k8s-auth-bearer-token", *fK8sAuthBearerToken))
506514

507515
srv.StaticUser = &auth.User{
508516
Token: *fK8sAuthBearerToken,
509517
}
510-
srv.ServiceAccountToken = *fK8sAuthBearerToken
518+
srv.InternalProxiedK8SClientConfig.BearerToken = *fK8sAuthBearerToken
511519
case "oidc", "openshift":
512520
flags.FatalIfFailed(flags.ValidateFlagIs("user-auth", authOptions.AuthType, "oidc", "openshift"))
513-
srv.ServiceAccountToken = k8sAuthServiceAccountBearerToken
521+
srv.InternalProxiedK8SClientConfig.BearerTokenFile = k8sInClusterBearerToken
514522
default:
515523
flags.FatalIfFailed(flags.NewInvalidFlagError("k8s-mode", "must be one of: service-account, bearer-token, oidc, openshift"))
516524
}
517525

518-
monitoringDashboardHttpClientTransport := &http.Transport{
519-
TLSClientConfig: srv.K8sProxyConfig.TLSClientConfig,
520-
}
521-
if *fK8sMode == "off-cluster" {
522-
monitoringDashboardHttpClientTransport.Proxy = http.ProxyFromEnvironment
526+
internalProxiedK8SRT, err := rest.TransportFor(srv.InternalProxiedK8SClientConfig)
527+
if err != nil {
528+
klog.Fatalf("Failed to create k8s HTTP client: %v", err)
523529
}
524530
srv.MonitoringDashboardConfigMapLister = server.NewResourceLister(
525-
srv.ServiceAccountToken,
526531
&url.URL{
527532
Scheme: k8sEndpoint.Scheme,
528533
Host: k8sEndpoint.Host,
@@ -531,14 +536,11 @@ func main() {
531536
"labelSelector": {"console.openshift.io/dashboard=true"},
532537
}.Encode(),
533538
},
534-
&http.Client{
535-
Transport: monitoringDashboardHttpClientTransport,
536-
},
539+
internalProxiedK8SRT,
537540
nil,
538541
)
539542

540543
srv.KnativeEventSourceCRDLister = server.NewResourceLister(
541-
srv.ServiceAccountToken,
542544
&url.URL{
543545
Scheme: k8sEndpoint.Scheme,
544546
Host: k8sEndpoint.Host,
@@ -547,16 +549,11 @@ func main() {
547549
"labelSelector": {"duck.knative.dev/source=true"},
548550
}.Encode(),
549551
},
550-
&http.Client{
551-
Transport: &http.Transport{
552-
TLSClientConfig: srv.K8sProxyConfig.TLSClientConfig,
553-
},
554-
},
552+
internalProxiedK8SRT,
555553
knative.EventSourceFilter,
556554
)
557555

558556
srv.KnativeChannelCRDLister = server.NewResourceLister(
559-
srv.ServiceAccountToken,
560557
&url.URL{
561558
Scheme: k8sEndpoint.Scheme,
562559
Host: k8sEndpoint.Host,
@@ -565,11 +562,7 @@ func main() {
565562
"labelSelector": {"duck.knative.dev/addressable=true,messaging.knative.dev/subscribable=true"},
566563
}.Encode(),
567564
},
568-
&http.Client{
569-
Transport: &http.Transport{
570-
TLSClientConfig: srv.K8sProxyConfig.TLSClientConfig,
571-
},
572-
},
565+
internalProxiedK8SRT,
573566
knative.ChannelFilter,
574567
)
575568

@@ -578,7 +571,7 @@ func main() {
578571
caCertFilePath = k8sInClusterCA
579572
}
580573

581-
if err := completedAuthnOptions.ApplyTo(srv, k8sEndpoint, apiServerEndpoint, caCertFilePath); err != nil {
574+
if err := completedAuthnOptions.ApplyTo(srv, k8sEndpoint, caCertFilePath); err != nil {
582575
klog.Fatalf("failed to apply configuration to server: %v", err)
583576
os.Exit(1)
584577
}
@@ -595,9 +588,14 @@ func main() {
595588
flags.FatalIfFailed(flags.NewInvalidFlagError("listen", "scheme must be one of: http, https"))
596589
}
597590

591+
consoleHandler, err := srv.HTTPHandler()
592+
if err != nil {
593+
klog.Errorf("failed to set up the console's HTTP handler: %v", err)
594+
os.Exit(1)
595+
}
598596
httpsrv := &http.Server{
599597
Addr: listenURL.Host,
600-
Handler: srv.HTTPHandler(),
598+
Handler: consoleHandler,
601599
// Disable HTTP/2, which breaks WebSockets.
602600
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
603601
TLSConfig: oscrypto.SecureTLSConfig(&tls.Config{}),

frontend/public/actions/features.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ const detectCanCreateProject = (dispatch) =>
208208
);
209209

210210
const detectUser = (dispatch) =>
211+
// FIXME: use k8s self-subject review API
211212
fetchURL('/apis/user.openshift.io/v1/users/~').then(
212213
(user) => {
213214
dispatch(setUser(user));

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/gorilla/websocket v1.4.2
1515
github.com/graph-gophers/graphql-go v1.5.0
1616
github.com/openshift/api v3.9.0+incompatible
17+
github.com/openshift/client-go v0.0.0-20230926161409-848405da69e1
1718
github.com/openshift/library-go v0.0.0-20231020125034-5a2d9fe760b3
1819
github.com/operator-framework/kubectl-operator v0.4.1-0.20230203190200-07b1999a3d68
1920
github.com/prometheus/client_golang v1.16.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,8 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3
10171017
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
10181018
github.com/openshift/api v0.0.0-20231025170628-b8a18fdc040d h1:076BQ9iaz/giM0wRT9grdbkYsdy6WHQ2vg/asQ3lv6c=
10191019
github.com/openshift/api v0.0.0-20231025170628-b8a18fdc040d/go.mod h1:qNtV0315F+f8ld52TLtPvrfivZpdimOzTi3kn9IVbtU=
1020+
github.com/openshift/client-go v0.0.0-20230926161409-848405da69e1 h1:W1N/3nVciqmjPjn2xldHjb0AwwCQzlGxLvX5BCgE8H4=
1021+
github.com/openshift/client-go v0.0.0-20230926161409-848405da69e1/go.mod h1:ihUJrhBcYAGYQrJu/gP2OMgfVds5f5z5kbeLNBqjHLo=
10201022
github.com/openshift/library-go v0.0.0-20231020125034-5a2d9fe760b3 h1:RmbS0Ea69/ejW0HqUoUjO72EfNc/biuVDjODEDl/EnE=
10211023
github.com/openshift/library-go v0.0.0-20231020125034-5a2d9fe760b3/go.mod h1:8UzmrBMCn7+GzouL8DVYkL9COBQTB1Ggd13/mHJQCUg=
10221024
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=

pkg/knative/handler.go

Lines changed: 45 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,79 +24,74 @@ import (
2424

2525
type KnativeHandler struct {
2626
trimURLPrefix string
27-
k8sClient *http.Client
28-
k8sEndpoint string
27+
anonConfig *rest.Config
2928
}
3029

31-
func NewKnativeHandler(trimURLPrefix string, k8sClient *http.Client, k8sEndpoint string) *KnativeHandler {
30+
func NewKnativeHandler(anonymousTransport http.RoundTripper, proxiedK8SEndpoint, trimURLPrefix string) *KnativeHandler {
3231
return &KnativeHandler{
33-
trimURLPrefix,
34-
k8sClient,
35-
k8sEndpoint,
32+
trimURLPrefix: trimURLPrefix,
33+
anonConfig: &rest.Config{
34+
Host: proxiedK8SEndpoint,
35+
Transport: anonymousTransport,
36+
},
3637
}
3738
}
3839

3940
func (h *KnativeHandler) generateClient(user *auth.User) (dynamic.Interface, error) {
40-
config := &rest.Config{
41-
Host: h.k8sEndpoint,
42-
Transport: h.k8sClient.Transport,
43-
BearerToken: user.Token,
44-
}
41+
config := rest.CopyConfig(h.anonConfig)
42+
config.BearerToken = user.Token
43+
4544
client, err := dynamic.NewForConfig(config)
4645
if err != nil {
47-
return nil, fmt.Errorf("Error creating dynamic client: %v", err)
46+
return nil, fmt.Errorf("error creating dynamic client: %v", err)
4847
}
4948
return client, nil
5049
}
5150

5251
func (h *KnativeHandler) Handle(user *auth.User, w http.ResponseWriter, r *http.Request) {
5352
parts := strings.Split(strings.Trim(strings.TrimPrefix(r.URL.Path, h.trimURLPrefix), "/"), "/")
5453

55-
if len(parts) >= 4 && parts[0] == "namespaces" && parts[2] == "services" {
56-
namespace := parts[1]
57-
service := parts[3]
54+
if len(parts) < 4 || parts[0] != "namespaces" || parts[2] != "services" {
55+
return
56+
}
57+
namespace := parts[1]
58+
service := parts[3]
5859

59-
// GET /namespaces/{namespace}/services/{service}/invoke
60-
if r.Method == http.MethodGet && len(parts) == 5 && parts[4] == "invoke" {
61-
serverutils.SendResponse(w, http.StatusMethodNotAllowed, serverutils.ApiError{Err: "Invalid method: only POST is allowed"})
62-
return
63-
}
60+
client, err := h.generateClient(user)
61+
if err != nil {
62+
klog.Errorf("Error creating dynamic client: %v", err)
63+
serverutils.SendResponse(w, http.StatusInternalServerError, serverutils.ApiError{Err: err.Error()})
64+
return
65+
}
6466

65-
// GET /namespaces/{namespace}/services/{service}/endpoints
66-
if r.Method == http.MethodGet && len(parts) == 5 && parts[4] == "endpoints" {
67-
client, err := h.generateClient(user)
68-
if err != nil {
69-
klog.Errorf("Error creating dynamic client: %v", err)
70-
serverutils.SendResponse(w, http.StatusInternalServerError, serverutils.ApiError{Err: err.Error()})
71-
return
72-
}
73-
url, err := getServiceEndpoints(client, namespace, service)
74-
if err != nil {
75-
klog.Errorf("Error Fetching Route URL for Knative Service: %v", err)
76-
serverutils.SendResponse(w, http.StatusInternalServerError, serverutils.ApiError{Err: err.Error()})
77-
return
78-
}
79-
serverutils.SendResponse(w, http.StatusOK, json.RawMessage(fmt.Sprintf(`{"url": "%s"}`, url)))
67+
// GET /namespaces/{namespace}/services/{service}/invoke
68+
if r.Method == http.MethodGet && len(parts) == 5 && parts[4] == "invoke" {
69+
serverutils.SendResponse(w, http.StatusMethodNotAllowed, serverutils.ApiError{Err: "Invalid method: only POST is allowed"})
70+
return
71+
}
72+
73+
// GET /namespaces/{namespace}/services/{service}/endpoints
74+
if r.Method == http.MethodGet && len(parts) == 5 && parts[4] == "endpoints" {
75+
url, err := getServiceEndpoints(client, namespace, service)
76+
if err != nil {
77+
klog.Errorf("Error Fetching Route URL for Knative Service: %v", err)
78+
serverutils.SendResponse(w, http.StatusInternalServerError, serverutils.ApiError{Err: err.Error()})
8079
return
8180
}
81+
serverutils.SendResponse(w, http.StatusOK, json.RawMessage(fmt.Sprintf(`{"url": "%s"}`, url)))
82+
return
83+
}
8284

83-
// POST /namespaces/{namespace}/services/{service}/invoke
84-
if r.Method == http.MethodPost && len(parts) == 5 && parts[4] == "invoke" {
85-
client, err := h.generateClient(user)
86-
if err != nil {
87-
klog.Errorf("Error creating dynamic client: %v", err)
88-
serverutils.SendResponse(w, http.StatusInternalServerError, serverutils.ApiError{Err: err.Error()})
89-
return
90-
}
91-
response, err := invokeService(client, namespace, service, r)
92-
if err != nil {
93-
klog.Errorf("Error During Knative Function Invokation: %v", err)
94-
serverutils.SendResponse(w, http.StatusInternalServerError, serverutils.ApiError{Err: err.Error()})
95-
return
96-
}
97-
serverutils.SendResponse(w, http.StatusOK, response)
85+
// POST /namespaces/{namespace}/services/{service}/invoke
86+
if r.Method == http.MethodPost && len(parts) == 5 && parts[4] == "invoke" {
87+
response, err := invokeService(client, namespace, service, r)
88+
if err != nil {
89+
klog.Errorf("Error During Knative Function Invokation: %v", err)
90+
serverutils.SendResponse(w, http.StatusInternalServerError, serverutils.ApiError{Err: err.Error()})
9891
return
9992
}
93+
serverutils.SendResponse(w, http.StatusOK, response)
94+
return
10095
}
10196
}
10297

pkg/server/kube_version.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ func (s *Server) GetKubeVersion() string {
1212
if s.KubeVersion != "" {
1313
return s.KubeVersion
1414
}
15-
config := &rest.Config{
16-
Host: s.K8sProxyConfig.Endpoint.String(),
17-
Transport: s.K8sClient.Transport,
18-
}
15+
config := s.InternalProxiedK8SClientConfig
1916

2017
kubeVersion, err := kubeVersion(config)
2118
if err != nil {

0 commit comments

Comments
 (0)