Skip to content

Commit

Permalink
Merge pull request #4 from kubevirt-ui/make-client-path-static
Browse files Browse the repository at this point in the history
Add a client-path parameter, and make the set token call vm specific
  • Loading branch information
yaacov authored May 30, 2024
2 parents f868db4 + c0f3954 commit 3e7e804
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 43 deletions.
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ FROM registry.access.redhat.com/ubi8/go-toolset:latest AS build
WORKDIR /app
COPY . .

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

# deploy stage
FROM registry.access.redhat.com/ubi8/ubi-minimal:latest
FROM registry.access.redhat.com/ubi9/ubi-minimal:latest

WORKDIR /app
RUN mkdir -p /app/web/public
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ Now that the virtual machine is running, we can create a signed link to the Kube
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

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

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

# Use the /auth/jwt/request endpoint to sign the token payload using the private key secret.
# The service account bearer token used in this command must be able to access the secret holding the private key.
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)

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

google-chrome "${signed_link}"
```
Expand Down
3 changes: 2 additions & 1 deletion cmd/kube-gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func main() {
publicDir := flag.String("public-dir", "./web/public", "localhost directory containing static web assets.")
basePath := flag.String("base-path", "/", "url endpoint for static web assets.")
apiPath := flag.String("api-path", "/k8s/", "url endpoint for API calls.")
clientPath := flag.String("client-path", "/noVNC/vnc_lite.html", "url endpoint for user client calls.")

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

// Register set token cookie endpoint
http.HandleFunc(setTokenEndpoint, token.SetToken)
http.HandleFunc(setTokenEndpoint, token.SetTokenFactory(*clientPath, *apiPath))

// Register static file server
fs := http.FileServer(http.Dir(*publicDir))
Expand Down
3 changes: 3 additions & 0 deletions deploy/kube-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ spec:
- command:
- ./kube-gateway
- -api-server=$(API_URL)
- -client-path=$(CLIENT_URL)
- -gateway-listen=$(LISTEN)
- -api-server-ca-file=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
- -api-server-bearer-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token
Expand All @@ -49,6 +50,8 @@ spec:
env:
- name: API_URL
value: https://kubernetes.default.svc
- name: CLIENT_URL
value: /noVNC/vnc_lite.html
- name: LISTEN
value: https://0.0.0.0:8080
image: quay.io/kubevirt-ui/kube-gateway
Expand Down
2 changes: 1 addition & 1 deletion deploy/route.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ metadata:
name: kube-gateway-route
namespace: kube-gateway
spec:
host: kube-gateway.apps.ironmaiden1.eng.lab.tlv.redhat.com
host: kube-gateway.apps-crc.testing
port:
targetPort: 8080
tls:
Expand Down
67 changes: 37 additions & 30 deletions pkg/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,40 +40,47 @@ type GateToken struct {
Token string
}

// SetToken handle callbacs from users manually setting the JWT cookie.
func SetToken(w http.ResponseWriter, r *http.Request) {
// Log request
glog.Infof("%s %v: %+v", r.RemoteAddr, r.Method, r.URL)

var token string
var then string
// HandlerFunc is a type alias for a function that handles HTTP requests.
type HandlerFunc func(w http.ResponseWriter, r *http.Request)

// Factory function that returns a SetTokenHandler
func SetTokenFactory(clientPath string, apiPath string) HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Log request
glog.Infof("%s %v: %+v", r.RemoteAddr, r.Method, r.URL)

var token string
var name string
var namespace string

// Get token and redirect from get request
if r.Method == http.MethodGet {
query := r.URL.Query()
token = query.Get("token")
name = query.Get("name")
namespace = query.Get("namespace")
}

// Get token and redirect from get request
if r.Method == http.MethodGet {
query := r.URL.Query()
token = query.Get("token")
then = query.Get("then")
}
// Get token and redirect from post request
if r.Method == http.MethodPost {
token = r.FormValue("token")
name = r.FormValue("name")
namespace = r.FormValue("namespace")
}

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

// Empty redirect, means go home
if then == "" {
then = "/"
// Set session cookie.
http.SetCookie(w, &http.Cookie{
Name: CookieName,
Value: token,
Path: "/",
SameSite: http.SameSiteLaxMode,
HttpOnly: true})
http.Redirect(w, r, then, http.StatusFound)
}

// Set session cookie.
http.SetCookie(w, &http.Cookie{
Name: CookieName,
Value: token,
Path: "/",
SameSite: http.SameSiteLaxMode,
HttpOnly: true})
http.Redirect(w, r, then, http.StatusFound)
}

// GetToken handle callbacs from OAuth2 authtorization server.
Expand Down
15 changes: 9 additions & 6 deletions web/public/login
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
function load() {
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
const then = urlParams.get('then');
const name = urlParams.get('name');
const namespace = urlParams.get('namespace');

document.getElementById("token").value = token
document.getElementById("then").value = then
document.getElementById("name").value = name
document.getElementById("namespace").value = namespace

if (token && then) {
if (token && name && namespace) {
document.getElementById("login").submit();
}
}
Expand All @@ -25,9 +27,10 @@
<form id="login" name="login" action="/auth/jwt/set" method="POST">
<label for="token">Token</label><br/>
<textarea name="token" id="token" rows="10" cols="40"></textarea><br/>
<label for="then">Then</label><br/>
<input id="then" name="then" size="35"/><br/>
<p class="help">For example: /noVNC/vnc_lite.html?path=k8s/apis/subresources.kubevirt.io/v1/namespaces/default/virtualmachineinstances/testvm/vnc<p>
<label for="name">Virtual machine name</label><br/>
<input id="name" name="name" size="35"/><br/>
<label for="namespace">Virtual machine namespace</label><br/>
<input id="namespace" name="namespace" size="35"/><br/>
<input type="submit" value="Submit">
</form>
</div>
Expand Down

0 comments on commit 3e7e804

Please sign in to comment.