Skip to content

Commit c0f3954

Browse files
committed
Add a client-path parameter, and make the set token call vm specific
Signed-off-by: yaacov <[email protected]>
1 parent f868db4 commit c0f3954

File tree

7 files changed

+60
-43
lines changed

7 files changed

+60
-43
lines changed

Dockerfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ FROM registry.access.redhat.com/ubi8/go-toolset:latest AS build
44
WORKDIR /app
55
COPY . .
66

7-
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /app/ /app/...
7+
USER 0
8+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -buildvcs=false -o /app/ /app/...
89

910
# deploy stage
10-
FROM registry.access.redhat.com/ubi8/ubi-minimal:latest
11+
FROM registry.access.redhat.com/ubi9/ubi-minimal:latest
1112

1213
WORKDIR /app
1314
RUN mkdir -p /app/web/public

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ Now that the virtual machine is running, we can create a signed link to the Kube
149149
kubectl get secrets -n kube-gateway -o json | jq '[.items[] | select(.metadata.name | contains("kube-gateway-sa")) | select(.type | contains("service-account-token")) | .data.token][0]' | python -m base64 -d > token
150150

151151
# Create a path to the k8s resource.
152-
path=/apis/subresources.kubevirt.io/v1/namespaces/kube-gateway/virtualmachineinstances/testvm/vnc
152+
name=testvm
153+
namespace=kube-gateway
154+
path=/apis/subresources.kubevirt.io/v1/namespaces/$namespace/virtualmachineinstances/$name/vnc
153155

154156
# Create a token payload for accessing the API path for 1 hour, starting now.
155157
data="{\"URLs\":[\"${path}\"],\"duration\":\"1h\"}"
@@ -158,15 +160,15 @@ token=$(cat token) # Use a k8s token that can access the private key for signing
158160
# On minikube get the url:
159161
# minikube service kube-gateway-svc -n kube-gateway
160162
# Important: the gateway is running with tls, make sure to use https://
161-
proxyurl=https://192.168.39.134:30345 # Use the URL of the gateway proxy
163+
proxyurl=https://kube-gateway.apps-crc.testing # Use the URL of the gateway proxy
162164

163165
# Use the /auth/jwt/request endpoint to sign the token payload using the private key secret.
164166
# The service account bearer token used in this command must be able to access the secret holding the private key.
165167
jwt=$(curl -sk -H 'Accept: application/json' -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" --request POST --data "${data}" "${proxyurl}/auth/jwt/request" | jq .Token)
166168

167169
# Open the link in a browser.
168170
# The link is signed using ${jwt} and will access the k8s API at ${path}.
169-
signed_link="${proxyurl}/auth/jwt/set?token=${jwt}&then=/noVNC/vnc_lite.html?path=k8s${path}"
171+
signed_link="${proxyurl}/auth/jwt/set?token=${jwt}&name=${name}&namespace=${namespace}"
170172

171173
google-chrome "${signed_link}"
172174
```

cmd/kube-gateway/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func main() {
3535
publicDir := flag.String("public-dir", "./web/public", "localhost directory containing static web assets.")
3636
basePath := flag.String("base-path", "/", "url endpoint for static web assets.")
3737
apiPath := flag.String("api-path", "/k8s/", "url endpoint for API calls.")
38+
clientPath := flag.String("client-path", "/noVNC/vnc_lite.html", "url endpoint for user client calls.")
3839

3940
apiServer := flag.String("api-server", "https://kubernetes.default.svc", "backend API server URL.")
4041
apiServerSkipVerifyTLS := flag.Bool("api-server-skip-verify-tls", false, "When true, skip verification of certs presented by k8s API server.")
@@ -170,7 +171,7 @@ func main() {
170171
http.Handle(s.APIPath, s.AuthMiddleware(s.APIProxy()))
171172

172173
// Register set token cookie endpoint
173-
http.HandleFunc(setTokenEndpoint, token.SetToken)
174+
http.HandleFunc(setTokenEndpoint, token.SetTokenFactory(*clientPath, *apiPath))
174175

175176
// Register static file server
176177
fs := http.FileServer(http.Dir(*publicDir))

deploy/kube-gateway.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ spec:
3838
- command:
3939
- ./kube-gateway
4040
- -api-server=$(API_URL)
41+
- -client-path=$(CLIENT_URL)
4142
- -gateway-listen=$(LISTEN)
4243
- -api-server-ca-file=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
4344
- -api-server-bearer-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token
@@ -49,6 +50,8 @@ spec:
4950
env:
5051
- name: API_URL
5152
value: https://kubernetes.default.svc
53+
- name: CLIENT_URL
54+
value: /noVNC/vnc_lite.html
5255
- name: LISTEN
5356
value: https://0.0.0.0:8080
5457
image: quay.io/kubevirt-ui/kube-gateway

deploy/route.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ metadata:
77
name: kube-gateway-route
88
namespace: kube-gateway
99
spec:
10-
host: kube-gateway.apps.ironmaiden1.eng.lab.tlv.redhat.com
10+
host: kube-gateway.apps-crc.testing
1111
port:
1212
targetPort: 8080
1313
tls:

pkg/token/token.go

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,40 +40,47 @@ type GateToken struct {
4040
Token string
4141
}
4242

43-
// SetToken handle callbacs from users manually setting the JWT cookie.
44-
func SetToken(w http.ResponseWriter, r *http.Request) {
45-
// Log request
46-
glog.Infof("%s %v: %+v", r.RemoteAddr, r.Method, r.URL)
47-
48-
var token string
49-
var then string
43+
// HandlerFunc is a type alias for a function that handles HTTP requests.
44+
type HandlerFunc func(w http.ResponseWriter, r *http.Request)
45+
46+
// Factory function that returns a SetTokenHandler
47+
func SetTokenFactory(clientPath string, apiPath string) HandlerFunc {
48+
return func(w http.ResponseWriter, r *http.Request) {
49+
// Log request
50+
glog.Infof("%s %v: %+v", r.RemoteAddr, r.Method, r.URL)
51+
52+
var token string
53+
var name string
54+
var namespace string
55+
56+
// Get token and redirect from get request
57+
if r.Method == http.MethodGet {
58+
query := r.URL.Query()
59+
token = query.Get("token")
60+
name = query.Get("name")
61+
namespace = query.Get("namespace")
62+
}
5063

51-
// Get token and redirect from get request
52-
if r.Method == http.MethodGet {
53-
query := r.URL.Query()
54-
token = query.Get("token")
55-
then = query.Get("then")
56-
}
64+
// Get token and redirect from post request
65+
if r.Method == http.MethodPost {
66+
token = r.FormValue("token")
67+
name = r.FormValue("name")
68+
namespace = r.FormValue("namespace")
69+
}
5770

58-
// Get token and redirect from post request
59-
if r.Method == http.MethodPost {
60-
token = r.FormValue("token")
61-
then = r.FormValue("then")
62-
}
71+
// Build the redirect URL
72+
cleanApiPath := apiPath[1:] // Remove prefix `/` from the begining of apiPath
73+
then := fmt.Sprintf("%s?path=%sapis/subresources.kubevirt.io/v1/namespaces/%s/virtualmachineinstances/%s/vnc", clientPath, cleanApiPath, namespace, name)
6374

64-
// Empty redirect, means go home
65-
if then == "" {
66-
then = "/"
75+
// Set session cookie.
76+
http.SetCookie(w, &http.Cookie{
77+
Name: CookieName,
78+
Value: token,
79+
Path: "/",
80+
SameSite: http.SameSiteLaxMode,
81+
HttpOnly: true})
82+
http.Redirect(w, r, then, http.StatusFound)
6783
}
68-
69-
// Set session cookie.
70-
http.SetCookie(w, &http.Cookie{
71-
Name: CookieName,
72-
Value: token,
73-
Path: "/",
74-
SameSite: http.SameSiteLaxMode,
75-
HttpOnly: true})
76-
http.Redirect(w, r, then, http.StatusFound)
7784
}
7885

7986
// GetToken handle callbacs from OAuth2 authtorization server.

web/public/login

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
function load() {
66
const urlParams = new URLSearchParams(window.location.search);
77
const token = urlParams.get('token');
8-
const then = urlParams.get('then');
8+
const name = urlParams.get('name');
9+
const namespace = urlParams.get('namespace');
910

1011
document.getElementById("token").value = token
11-
document.getElementById("then").value = then
12+
document.getElementById("name").value = name
13+
document.getElementById("namespace").value = namespace
1214

13-
if (token && then) {
15+
if (token && name && namespace) {
1416
document.getElementById("login").submit();
1517
}
1618
}
@@ -25,9 +27,10 @@
2527
<form id="login" name="login" action="/auth/jwt/set" method="POST">
2628
<label for="token">Token</label><br/>
2729
<textarea name="token" id="token" rows="10" cols="40"></textarea><br/>
28-
<label for="then">Then</label><br/>
29-
<input id="then" name="then" size="35"/><br/>
30-
<p class="help">For example: /noVNC/vnc_lite.html?path=k8s/apis/subresources.kubevirt.io/v1/namespaces/default/virtualmachineinstances/testvm/vnc<p>
30+
<label for="name">Virtual machine name</label><br/>
31+
<input id="name" name="name" size="35"/><br/>
32+
<label for="namespace">Virtual machine namespace</label><br/>
33+
<input id="namespace" name="namespace" size="35"/><br/>
3134
<input type="submit" value="Submit">
3235
</form>
3336
</div>

0 commit comments

Comments
 (0)