-
Notifications
You must be signed in to change notification settings - Fork 229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Secure access to in-cluster headlamp with a reverse proxy #2207
Comments
Hi @mlbiam , while I'd like to understand what this implies for the project (what dependencies it brings, what we have to maintain, does UX change at all?), in principle we agree with having ways of deploying Headlamp that improve security or validate different use-cases. So I am happy to work with you to land this. |
Hi, We can use the example of weavworks GitOps dashboard, where the OIDC authenticates the user to the application, the dashboard application then sends the user impersonation token in each request to the API server (application needs a service account with impersonation of user and group). This will also translate nicely to already configured RBAC in the cluster, e.g. if cluster admins have already configured the same groups as returned in user's token References: |
@umarhussain15 this is how it works with the current Kubernetes Dashboard too |
Thanks for the pointers. We definitely want to support this as an option. |
Oh, looks like the website is taken down now as well, as weaveworks shutdown. |
for reference, here's the PR that enabled this in the Kubernetes Dashboard - https://github.com/kubernetes/dashboard/pull/4082/commits |
As a cluster admin trying to migrate from Weave GitOps to Headlamp in-cluster I am impressed by the product. However the lack of impersonation support through OIDC login is a unfortunately a blocker for adoption by developer teams in my org... |
Linking the new PR which will enable it 🎉 |
can you explain this please? AFAIU the client secret will be set by the admin in in-cluster deployment only, why will there be a need to distribute client secret? |
I took a look into the OIDC impersonation implementation in Kubernetes Dashboard. From my understanding, adding OIDC Impersonation support in Headlamp is not so straight forward as Kubernetes Dashboard. In Kubernetes Dashboard the client is created for every request with the impersonation details, where as in headlamp a proxy to the Kubernetes api-server is established in the beginning and requests are proxied with the authentication headers from frontend. Right now we have one proxy per cluster, if we want to support impersonation (which involves adding impersonation details to clientcmd/api.AuthInfo) we will have to create one proxy per user per cluster. handleImpersonation is used in Client and the client is initialised in all the requests 1 2... |
If you require a client secret for a client in your identity provider, it must always be used. In this case, that means both server side applications like headlamp and cli applications like kubectl. This is why Kuberentes made client secrets optional, distributing the client secret to anyone using kubectl is impractical (and gets treated as a password by most enterprise compliance requirements causing all kinds of headaches). Since Kubernetes can only support a single issuer (this changes in 1.30 but is still in beta and is not available for commercial distributions yet), it means that your identity provider can't be split up between a CLI idp and a server side idp. So that means to use both headlamp in-cluster and kubectl you'd need to distribute the client secret to anyone using kubectl |
Correct
you support oidc now, don't you have the same problem? If you have two users signed in via OIDC, how do you keep their sessions separate? If you're not maintaining user specific connections, that means a user with admin access to a specific namespace could use the credentials of a user with cluster-admin access??? Even two users with the same permission levels would have an issue because the audit logs could show either one as the user that executed an action. That sounds like a significant security issue. |
For a cluster configured with OIDC the proxy that is created is an unauthenticated proxy that can be used by anyone with proper auth headers. Once the user completes the OIDC flow the code that is returned in the callback is exchanged for a token and is sent to the frontend, the frontend sends the token in Authorization header which is forwaded to the proxy. So I don't see permission mismatch issues. |
AFAIU A different client can be created in the IDP for headlamp right? As long as the token that is provided by the client with secret has the claims that are accepted by the kubernetes api-server it should work without any hassle. |
I just came across user-impersonation, as long as the reverse proxy adds the proper impersonation headers to the proxied requests, headlamp will forward it to the api-server and it should work as expected. Can you share the logs or any other info that can help me understand the errors that you faced with impersonation? |
no, kubernetes also gets configured with an expected client via |
tbc, you're saying that every request to the API server from headlamp has a unique
i havne't tested out the PR yet, but based on your description is should be OK. i'm more concerned about your original statement that the proxy is tied to a cluster, not a user. For impersonation to work correctly you should be passing the token and the impersonation headers on every request to the API server. I've not reviewed the PR yet to confirm that's what's happening. |
Yes, the token is stored in the frontend and sent with every request to the cluster.
The proxy created by the backend is cluster-specific. The user information is sent by the frontend, so we only need a single proxy per cluster.
I'm setting up Headlamp with OpenUnison to verify if this works as expected. I'll update here once I have tested it. |
@yolossn feel free to ping me in the headlamp slack |
Quick Update, I was able to test if the Impersonation headers are working without installing openunison by a workaround. I used AKS with Entra ID auth setup for this.
kubectl apply -f config.yaml
# 1. Role for the admin user who will perform impersonation
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: impersonator
rules:
- apiGroups: [""]
resources: ["users", "groups"]
verbs: ["impersonate"]
---
# 2. Binding for the admin user
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: impersonator-binding
subjects:
- kind: User
name: admin-user # The user who will be doing the impersonation
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: impersonator
apiGroup: rbac.authorization.k8s.io
---
# 3. Role for test-user2
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: test-user2-role
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
# 4. Binding for test-user2
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-user2-binding
namespace: default
subjects:
- kind: User
name: test-user2
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: test-user2-role
apiGroup: rbac.authorization.k8s.io
![]()
![]()
kubelogin get-token --login azurecli --server-id <your-server-id> Note: server-id can be retrieved from the kubeconfig exec
curl --location 'http://localhost:4000/headlamp/clusters/main/api/v1/namespaces/default/services' \
--header 'Accept: */*' \
--header 'Authorization: Bearer <your-admin-token>' ![]() curl --location 'http://localhost:4000/headlamp/clusters/main/api/v1/namespaces/default/pods' \
--header 'Accept: */*' \
--header 'Authorization: Bearer <your-admin-token>' ![]() With the admin token both services and pods should be accessible
curl --location 'http://localhost:4000/headlamp/clusters/main/api/v1/namespaces/default/pods' \
--header 'Accept: */*' \
--header 'Impersonate-User: test-user2' \
--header 'Authorization: Bearer <your-admin-token>' ![]() curl --location 'http://localhost:4000/headlamp/clusters/main/api/v1/namespaces/default/services' \
--header 'Accept: */*' \
--header 'Impersonate-User: test-user2' \
--header 'Authorization: Bearer <your-admin-token>' ![]() With user impersonation headers only pods should be accessible, services should through 403 forbidden error This showcases that proxy that is created by headlamp to the cluster supports Impersonation out of the box. @mlbiam If you can point me to a doc for using openunison as an oidc proxy with impersonation configurations. I will test that too. |
@yolossn to deploy with entra:
Once you're able to login to your cluster, add this to your openunison values.yaml: openunison:
apps:
- name: headlamp
label: Headlamp
org: b1bf4c92-7220-4ad2-91af-ee0fe0af7312
badgeUrl: https://headlamp-ingress.domain.com/
injectToken: true
proxyTo: http://healamp.headlamp.svc${fullURI}
azGroup:
- group_from_entraid
icon: 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dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6R0lNUD0iaHR0cDovL3d3dy5naW1wLm9yZy94bXAvIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgIHhtcE1NOkRvY3VtZW50SUQ9ImdpbXA6ZG9jaWQ6Z2ltcDpkYjhlYTRhMS1iN2U4LTQyZjItOGMxYy0zNDgxZDQ0YWY1NTYiCiAgIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MmE5YzE1NTctZTExMS00N2QxLWE5ZDMtZTY5MDgxY2NhMjJmIgogICB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ZTJiZjljOGEtOTc5My00ZTk1LWIxNDMtM2U5NDBmMjk4NjcyIgogICBkYzpGb3JtYXQ9ImltYWdlL3BuZyIKICAgR0lNUDpBUEk9IjIuMCIKICAgR0lNUDpQbGF0Zm9ybT0iTWFjIE9TIgogICBHSU1QOlRpbWVTdGFtcD0iMTc0MDUzNDM2Mjg3MDM2OSIKICAgR0lNUDpWZXJzaW9uPSIyLjEwLjI4IgogICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICB4bXA6Q3JlYXRvclRvb2w9IkdJTVAgMi4xMCI+CiAgIDx4bXBNTTpIaXN0b3J5PgogICAgPHJkZjpTZXE+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249InNhdmVkIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjZlMmI3MDRhLWQzN2QtNGE3Yi04NjRhLWFlZjFjZTRjMjBlMCIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iR2ltcCAyLjEwIChNYWMgT1MpIgogICAgICBzdEV2dDp3aGVuPSIyMDI1LTAyLTI1VDIwOjQ2OjAyLTA1OjAwIi8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PpSPVkAAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfpAhoBLgJcMAZGAAAgAElEQVR42u2deZRcxXX/P7fqvdc9qxYkgRC7EEhgsTkW4hcg4ZDgDesX5PUYfkbegBA5sWPsY2x8gAQb84sJEIJjMDLewmJAYBsDBhsTMEsAAUImAqPFBgYhCSSNZuvu917d3x+vuxmI84sdMzPd4n7OqTM9I810v6r6Vt26desWGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGIZhGEabIVYFrz8XXHDBgksuueQjlUqFUqmEqrbcZzziiCP8TTfd9HFrrdeHyKrg9Wfbtm37bdiw4VQRQVVbUkgvvfQSgAnJhNTC03xdQN578jxHpPUm/hCCNZQJqbUJISAi5HnekrMRQBzH1lCvI86qYAwq1bmWFVCDPM+toUxIhmFCMgwTkmEYJiTDMCEZhgnJMExIhmGYkAzDhGQYJiTDMCEZhmFCmjB6enqmiUhLRn03GBwc5PHHH59irfX6YAf7XiduvfXWnXp7e8+47rrrTn744YdnPvLII4QQWva4QrlcZuHChSMnn3zywIYNG+affPLJtVmzZm2z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 Then update the Create an Login to OpenUnison, there will now be a Headlamp badge |
I'd like to integrate HeadLamp into OpenUnison (https://openunison.github.io), but I'm running into a few issues:
OIDC doesn't support self signed CA - Going through the instructions for OIDC ignores trusting a certificate. This makes OIDC mostly useless for identity prociders that aren't publicly hosted, like OpenUnison, in an enterprise environment which usually has its own internal CA.
OIDC uses a client secret - Kubernetes will require the audience to be the same for kubectl and your cluster, but that means that using client secret means all kubectl users also need a client secret (this is technically not true with 1.30+, but additional token types will take quite some time to be available, if ever, to commercial distributions and managed clusters). Distributing a client secret is an anti pattern for kubectl use because it's now a shared password and will need to be treated as such by more enterprise security policies.
OIDC doesn't support impersonation - There's no way to integrate incluster headlamp with a managed cluster.
For these reasons, I'd like to propose a reverse proxy approach for in-cluster, similar to how the Kubernetes Dashboard, Kiali (Istio Dashboard), and the Tekton Dashboard all work. A revesrse proxy architecture allows a revese proxy, such as OpenUnison or OAuth2 proxy, to inject a token, and potentially impersonation headers, into each request. It then becomes the responsibility of the reverse proxy to keep the authentication token (and impersonation headers) up to date.
I'm happy to contribute code to make this work, but I want to make sure the project is willing to integrate this feature before I dive into doing the work.
The text was updated successfully, but these errors were encountered: