diff --git a/slides/k8s/kubectlproxy.md b/slides/k8s/kubectlproxy.md index 6ae9f4c5..883f6e50 100644 --- a/slides/k8s/kubectlproxy.md +++ b/slides/k8s/kubectlproxy.md @@ -1,4 +1,71 @@ -# Accessing internal services with `kubectl proxy` +# Accessing the API with `kubectl proxy` + +- The API requires us to authenticate.red[¹] + +- There are many authentication methods available, including: + + - TLS client certificates +
+ (that's what we've used so far) + + - HTTP basic password authentication +
+ (from a static file; not recommended) + + - various token mechanisms +
+ (detailed in the [documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authentication-strategies)) + +.red[¹]OK, we lied. If you don't authenticate, you are considered to +be user `system:anonymous`, which doesn't have any access rights by default. + +--- + +## Accessing the API directly + +- Let's see what happens if we try to access the API directly with `curl` + +.exercise[ + +- Retrieve the ClusterIP allocated to the `kubernetes` service: + ```bash + kubectl get svc kubernetes + ``` + +- Replace the IP below and try to connect with `curl`: + ```bash + curl -k https://`10.96.0.1`/ + ``` + +] + +The API will tell us that user `system:anonymous` cannot access this path. + +--- + +## Authenticating to the API + +If we wanted to talk to the API, we would need to: + +- extract our TLS key and certificate information from `~/.kube/config` + + (the information is in PEM format, encoded in base64) + +- use that information to present our certificate when connecting + + (for instance, with `openssl s_client -key ... -cert ... -connect ...`) + +- figure out exactly which credentials to use + + (once we start juggling multiple clusters) + +- change that whole process if we're using another authentication method + +🤔 There has to be a better way! + +--- + +## Using `kubectl proxy` for authentication - `kubectl proxy` runs a proxy in the foreground @@ -10,15 +77,40 @@ - This is a great tool to learn and experiment with the Kubernetes API -- The Kubernetes API also gives us a proxy to HTTP and HTTPS services +- ... And for serious usages as well (suitable for one-shot scripts) -- Therefore, we can use `kubectl proxy` to access internal services - - (Without using a `NodePort` or similar service) +- For unattended use, it is better to create a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) --- -## Secure by default +## Trying `kubectl proxy` + +- Let's start `kubectl proxy` and then do a simple request with `curl`! + +.exercise[ + +- Start `kubectl proxy` in the background: + ```bash + kubectl proxy & + ``` + +- Access the API's default route: + ```bash + curl localhost:8001 + ``` + +- Terminate the proxy: + ```bash + kill %1 + ``` + +] + +The output is a list of available API routes. + +--- + +## `kubectl proxy` is intended for local use - By default, the proxy listens on port 8001 @@ -34,84 +126,54 @@ - This is great when running `kubectl proxy` locally -- Not-so-great when running it on a remote machine +- Not-so-great when you want to connect to the proxy from a remote machine --- ## Running `kubectl proxy` on a remote machine -- We are going to bind to `INADDR_ANY` instead of `127.0.0.1` +- If we wanted to connect to the proxy from another machine, we would need to: -- We are going to accept connections from any address + - bind to `INADDR_ANY` instead of `127.0.0.1` -.exercise[ + - accept connections from any address -- Run an open proxy to the Kubernetes API: +- This is achieved with: ``` kubectl proxy --port=8888 --address=0.0.0.0 --accept-hosts=.* ``` -] - -.warning[Anyone can now do whatever they want with our Kubernetes cluster! -
-(Don't do this on a real cluster!)] +.warning[Do not do this on a real cluster: it opens full unauthenticated access!] --- -## Viewing available API routes +## Security considerations -- The default route (i.e. `/`) shows a list of available API endpoints +- Running `kubectl proxy` openly is a huge security risk -.exercise[ +- It is slightly better to run the proxy where you need it -- Point your browser to the IP address of the node running `kubectl proxy`, port 8888 + (and copy credentials, e.g. `~/.kube/config`, to that place) -] - -The result should look like this: -```json -{ - "paths": [ - "/api", - "/api/v1", - "/apis", - "/apis/", - "/apis/admissionregistration.k8s.io", - … -``` +- It is even better to use a limited account with reduced permissions --- -## Connecting to a service through the proxy +## Good to know ... -- The API can proxy HTTP and HTTPS requests by accessing a special route: +- `kubectl proxy` also gives access to all internal services + +- Specifically, services are exposed as such: ``` - /api/v1/namespaces/`name_of_namespace`/services/`name_of_service`/proxy + /api/v1/namespaces//services//proxy ``` -- Since we now have access to the API, we can use this special route +- We can use `kubectl proxy` to access an internal service in a pinch -.exercise[ + (or, for non HTTP services, `kubectl port-forward`) -- Access the `hasher` service through the special proxy route: - ```open - http://`X.X.X.X`:8888/api/v1/namespaces/default/services/hasher/proxy - ``` +- This is not very useful when running `kubectl` directly on the cluster -] - -You should see the banner of the hasher service: `HASHER running on ...` - ---- - -## Stopping the proxy - -- Remember: as it is running right now, `kubectl proxy` gives open access to our cluster - -.exercise[ - -- Stop the `kubectl proxy` process with Ctrl-C - -] + (since we could connect to the services directly anyway) +- But it is very powerful as soon as you run `kubectl` from a remote machine