Skip to content

config: support username impersonation #2373

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

cjihrig
Copy link
Contributor

@cjihrig cjihrig commented Apr 15, 2025

This commit adds support for username impersonation. This does not implement group, UID, or extra impersonation.

Refs: #2355

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: cjihrig

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Apr 15, 2025
@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Apr 16, 2025
@mstruebing
Copy link
Member

The changes looks good to me - should we wait for @Dimpison to confirm?

@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 18, 2025

I'm OK with moving it forward since it's been a few days. I did test in a real cluster, and it seemed to work.

@Dimpison
Copy link

Apologies for the late reply. I will test it tomorrow morning and update here.

@Dimpison
Copy link

I might be doing smth wrong, or it seems like it works slightly differently than it's expected to work.
Below is the code that I used for testing

import * as k8s from "@kubernetes/client-node";

const KUBECONFIG_PATH = "/Users/Dmytro_Kabachenko/.kube/config";
const KUBE_CONFIG = new k8s.KubeConfig();
KUBE_CONFIG.loadFromFile(KUBECONFIG_PATH);
const K8S_CLIENT = k8s.KubernetesObjectApi.makeApiClient(KUBE_CONFIG);
K8S_CLIENT.defaultNamespace = "my-namespace";

console.log(KUBE_CONFIG.getCurrentUser());

const secretTemplate = {
  apiVersion: "v1",
  kind: "Secret",
  metadata: {
    name: "my-secret",
  },
};

const secret = K8S_CLIENT.read(secretTemplate);

console.log(secret);

package.json

  "dependencies": {
    "@kubernetes/client-node": "file:../javascript",

git repo

❯ git remote show origin
* remote origin
  Fetch URL: https://github.com/cjihrig/javascript.git
  Push  URL: https://github.com/cjihrig/javascript.git
  HEAD branch: master
  Remote branches:
    doc              tracked
    impersonate      tracked
    master           tracked
    promises         tracked
    release-1.x      tracked
    revert           tracked
    test             tracked
    transpiled-tests tracked
    url-parse        tracked
  Local branches configured for 'git pull':
    impersonate merges with remote impersonate
    master      merges with remote master
  Local refs configured for 'git push':
    impersonate pushes to impersonate (up to date)
    master      pushes to master      (up to date)
❯ git status
On branch impersonate
Your branch is up to date with 'origin/impersonate'.

nothing to commit, working tree clean

kubeconfig user configuration

- name: my-user
  user:
    as: "my-namespace-sudo"
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - eks
      - get-token
      - --cluster-name=my-cluster
      command: aws

Output from the code execution

❯ node src/index.js
{
  authProvider: undefined,
  certData: undefined,
  certFile: undefined,
  exec: {
    apiVersion: 'client.authentication.k8s.io/v1beta1',
    args: [ 'eks', 'get-token', '--cluster-name=my-cluster' ],
    command: 'aws'
  },
  keyData: undefined,
  keyFile: undefined,
  name: 'my-user,
  token: undefined,
  password: undefined,
  username: undefined,
  impersonateUser: undefined
}
Promise { <pending> }
file:///Users/Dmytro_Kabachenko/javascript/dist/object.js:466
        throw new ApiException(response.httpStatusCode, 'Unsuccessful HTTP Request', await response.getBodyAsAny(), response.headers);
              ^

ApiException [Error]: HTTP-Code: 403
Message: Unsuccessful HTTP Request
Body: "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"secrets \\\"my-secret\\\" is forbidden: User \\\"AWS_ROLE_ARN\\\" cannot get resource \\\"secrets\\\" in API group \\\"\\\" in the namespace \\\"my-namespace\\\"\",\"reason\":\"Forbidden\",\"details\":{\"name\":\"my-secret\",\"kind\":\"secrets\"},\"code\":403}\n"
Headers: {SKIPPED}
    at KubernetesObjectApi.processResponse (file:///Users/Dmytro_Kabachenko/javascript/dist/object.js:466:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  code: 403,
  body: 'SKIPPED',
  headers: {SKIPPED}
}

Node.js v20.19.0

The kubectl works w/ no issues and returns the same 403 when I remove the as keyword in kubeconfig.

@mstruebing
Copy link
Member

@Dimpison one obvious question: Did you rebuild the kubernetes client?

i.e. npm install && npm run build

@brendandburns
Copy link
Contributor

I think that if you use kubectl --v=10 ... you should be able to see exactly what kubectl is sending across HTTP and then diff it with what we're sending.

@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 19, 2025

Do you need to allow the impersonate verb?

@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 19, 2025

impersonateUser: undefined

I think this is the problem. When I add as: impersonated-user to my own kubeconfig and run console.log(kc.getCurrentUser()); I see impersonateUser: 'impersonated-user' logged. This is how I tested that just now:

import * as k8s from './dist/index.js';
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
console.log(kc.getCurrentUser());

EDIT: Oh, it looks like I have as on the wrong object in the kubeconfig. I think it should be on the user object, not a peer to it.

This commit adds support for username impersonation. This does
not implement group, UID, or extra impersonation.

Refs: kubernetes-client#2355
@Dimpison
Copy link

@mstruebing , sure. I think I can’t run my code w/o building the dependency.

@Dimpison
Copy link

@cjihrig , will be able to check it on Wednesday. Sorry, for the delay. The “as” field should be in here “users.user.as”. At the same level as “exec”. See example of a single entry in “users” above.

@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 20, 2025

The “as” field should be in here “users.user.as”.

Yep, I moved it there.

@Dimpison
Copy link

@cjihrig, it works fine now. Thx a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants