cloudfoundry / cf-crd-explorations

Apache License 2.0
3 stars 2 forks source link

Explore: prepare a proposal for our CLI changes #72

Closed gcapizzi closed 3 years ago

gcapizzi commented 3 years ago

The bulk of our authentication support work will happen in the cf CLI. The idea is to change the CLI so that, when pointed at a cf-k8s foundation, it leverages the user's $KUBECONFIG and possibly code from client-go to authenticate exactly in the same way as kubectl would.

In #62 we have proved that we can support $KUBECONFIG and reuse a lot of client-go functionality, while implementing the same interface the CLI already uses for UAA-based authentication.

Now we need to get a more thorough understanding of all changes needed to implement our strategy. Some questions that come to mind:

The result might look a bit like a Kubernetes Enhancement Proposal although probably not so detailed!

Deliverable

Let's start this on a Google Doc, and then eventually open a GItHub issue on the CLI repository once we reach agreement in the team.

gcapizzi commented 3 years ago

I have taken a quick look at the CLI codebase, and in particular at the cf api command.

The command delegates to Actor.SetTarget, which, in order:

  1. initialises the Cloud Controller client;
  2. calls the CF root endpoint;
  3. stores the results in the configuration.

Config gets loaded in the CommandParser and then passed to each command via the Setup method. It gets then used to instantiate the wrapped clients, so it is available when the wrappers are wired in. This means that we could instantiate a different ConnectionWrapper based on the Config:

gcapizzi commented 3 years ago

Today I systematically searched for all the code paths that used a UAAClient. Here is the list of Actor methods that do, alongside the commands they get invoked from:

Some observations:

gcapizzi commented 3 years ago

@emalm had an interesting question on our authentication doc: can we leverage cf login to allow users to choose one of the AuthInfos stored in $KUBECONFIG vs trying to detect it automatically? The answer is yes!

This is what cf login does:

Here is how we could modify it:

This flow looks more intuitive and more similar to what CF users already do. It also does not need the Kubernetes cluster URL, which simplifies the shim implementation, as the root endpoint could just return a "kubernetes": true flag.

gcapizzi commented 3 years ago

Methods trying to parse the JWT token:

The Actor methods are only invoked in cf logs and cf oauth-token, which we can ignore for now. We're going to provide an alternative ConnectionWrapper implementation to UAAAuthentication, so we don't care about that either.

Unfortunately the Config methods are called literally everywhere. I have identified three reasons:

  1. to print user info on screen;
  2. to check if the user is logged in;
  3. in CreateSpaceCommand, the CLI assigns the roles of Space Manager and Space Developer to the user creating the space.

The username from $KUBECONFIG is usually not a user name, but a cluster name. It could be fine for 1 and 2, but not for 3. I can think of two strategies to handle this:

  1. Implement our own CurrentUser to return the real username, using the techniques described here to introduce a /whoami endpoint.
  2. Add some conditional logic in CreateSpaceRole which ignores the userNameOrGUID argument if it's equal to the current output of CurrentUser. The shim could then default the username to the one in the token if it's missing.
gcapizzi commented 3 years ago

Today I'm looking at a couple of other interfaces that we might have to (partially) reimplement:

danail-branekov commented 3 years ago

We started hacking the cli and try to integrate it with cfshim and we scoredcertain progress.

Setting up the dev environment:

Behold!

❯ ./cli api http://localhost:9000
Setting API endpoint to http://localhost:9000...
Warning: Insecure http API endpoint detected: secure https API endpoints are recommended
OK

API endpoint:   http://localhost:9000
API version:

Not logged in. Use 'cli login' or 'cli login --sso' to log in.
❯ ./cli login
API endpoint: http://localhost:9000
Warning: Insecure http API endpoint detected: secure https API endpoints are recommended
Warning: unable to determine whether targeted API's version meets minimum supported.

1. alice
2. gke_cff-eirini-peace-pods_europe-west1-b_cf4k8s4a8e
3. gke_cff-eirini-peace-pods_europe-west1-b_dex-pinniped
4. gke_cff-eirini-peace-pods_europe-west1-b_pinniped
5. kind-cross-org-1
6. kind-cross-org-2
7. kind-dex-play

Choose your Kubernetes user (enter to skip): 1

Authenticating...
OK

Targeted org foo.

Targeted space bar.

API endpoint:   http://localhost:9000
API version:
user:           alice
org:            foo
space:          bar

The cli would show a menu with the entries from kubeconfig, note that alice is there! After being chosen, the UI reports that you are logged in as alice

❯ ./cli apps
Getting apps in org foo / space bar as alice...

Unexpected Response
Response Code: 500
Code: 0, Title: , Detail: {"errors":[{"detail":"error fetching app: apps.apps.cloudfoundry.org is forbidden: User \"oidc:alice@vcap.me\" cannot list resource \"apps\" in API group \"apps.cloudfoundry.org\" at the cluster scope","title":"ServerError","code":10001}]}

FAILED

Good, we are hitting the shim with alice's JWT token so K8S knows who we are. alice is not allowed to do that though... yet

❯ k apply -f ~/workspace/auth-explore/run-cfshim/alice-viewer-rolebinding.yml
clusterrolebinding.rbac.authorization.k8s.io/alice-viewer created
clusterrole.rbac.authorization.k8s.io/app-viewer created
clusterrolebinding.rbac.authorization.k8s.io/alice-apps-viewer created

❯ ./cli apps
Getting apps in org foo / space bar as alice...

No apps found

Let's create an app and try to list it:

❯ k apply -f ~/workspace/cf-crd-explorations/config/samples/cf-crds/app.yaml
app.apps.cloudfoundry.org/my-app-guid created

~/workspace/cli wip-k8s
❯ ./cli apps
Getting apps in org foo / space bar as alice...

Error unmarshalling the following into a cloud controller error: 404 page not found

FAILED

This error is caused by the shim not implementing the /processes endpoint. However, this is irrelevant to the spike

mnitchev commented 3 years ago

Blocking until the rest of the team can take a look at the draft proposal here

emalm commented 3 years ago

@mnitchev, could you please grant global comment-level access to that proposal doc? Thanks!

kieron-dev commented 3 years ago

@emalm - global comment-level enabled.