Skip to content

Commit

Permalink
Switch to service account after logging into OpenShift Sandbox
Browse files Browse the repository at this point in the history
The service account will remain authenticated for longer than 15
minutes.

To try this out:
1. Log into an OpenShift Sandbox cluster using the Login workflow
2. Run `oc whoami`. You should see a reference to `pipeline`, which is the
   serviceaccount that's being used
3. The Application Explorer should display you as logged in and work as
   expected

Closes #3838

Signed-off-by: David Thompson <davthomp@redhat.com>
  • Loading branch information
datho7561 authored and vrubezhny committed Feb 5, 2024
1 parent bb366f5 commit eb06f1c
Showing 1 changed file with 62 additions and 16 deletions.
78 changes: 62 additions & 16 deletions src/openshift/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
*-----------------------------------------------------------------------------------------------*/

import { KubernetesObject } from '@kubernetes/client-node';
import { Cluster as KcuCluster, Context as KcuContext } from '@kubernetes/client-node/dist/config_types';
import * as fs from 'fs/promises';
import * as YAML from 'js-yaml';
import { ExtensionContext, QuickInputButtons, QuickPickItem, QuickPickItemButtonEvent, ThemeIcon, Uri, commands, env, window, workspace } from 'vscode';
import { CommandText } from '../base/command';
import { CliChannel } from '../cli';
Expand All @@ -14,15 +17,14 @@ import * as NameValidator from '../openshift/nameValidator';
import { TokenStore } from '../util/credentialManager';
import { Filters } from '../util/filters';
import { inputValue, quickBtn } from '../util/inputValue';
import { KubeConfigUtils } from '../util/kubeUtils';
import { KubeConfigUtils, getKubeConfigFiles } from '../util/kubeUtils';
import { LoginUtil } from '../util/loginUtil';
import { Platform } from '../util/platform';
import { Progress } from '../util/progress';
import { VsCommandError, vsCommand } from '../vscommand';
import { OpenShiftTerminalManager } from '../webview/openshift-terminal/openShiftTerminal';
import OpenShiftItem, { clusterRequired } from './openshiftItem';
import fetch = require('make-fetch-happen');
import { Cluster as KcuCluster, Context as KcuContext } from '@kubernetes/client-node/dist/config_types';

export interface QuickPickItemExt extends QuickPickItem {
name: string,
Expand Down Expand Up @@ -838,20 +840,26 @@ export class Cluster extends OpenShiftItem {
} else {
ocToken = userToken;
}
return Progress.execFunctionWithProgress(`Login to the cluster: ${clusterURL}`, () =>
Oc.Instance.loginWithToken(clusterURL, ocToken)
.then(() => Cluster.loginMessage(clusterURL))
.catch((error) =>
Promise.reject(
new VsCommandError(
`Failed to login to cluster '${clusterURL}' with '${Filters.filterToken(
error.message,
)}'!`,
'Failed to login to cluster',
),
),
),
);
return Progress.execFunctionWithProgress(`Login to the cluster: ${clusterURL}`, async () => {
try {
await Oc.Instance.loginWithToken(clusterURL, ocToken);
if (Cluster.isOpenShiftSandbox(clusterURL)) {
const YES = 'Yes';
const result = await window.showInformationMessage('OpenShift Sandbox logs you out after 15 minutes. Would you like to switch to a service account to prevent this?', YES, 'No');
if (result === YES) {
await Cluster.installPipelineUserContext();
}
}
return Cluster.loginMessage(clusterURL);
} catch (error) {
throw new VsCommandError(
`Failed to login to cluster '${clusterURL}' with '${Filters.filterToken(
error.message,
)}'!`,
'Failed to login to cluster',
);
}
});
}

static validateLoginToken(token: string): boolean {
Expand All @@ -878,6 +886,39 @@ export class Cluster extends OpenShiftItem {
return Cluster.tokenLogin(apiEndpointUrl, true, clipboard);
}

static async installPipelineUserContext(): Promise<void> {
const kcu = new KubeConfigUtils();
const kcFiles = getKubeConfigFiles();
if (kcFiles.length === 0) {
throw new Error('Could not locate Kube Config when trying to replace OpenShift Sandbox token with a longer-lived token');
}
const kcPath = kcFiles[0];
const kcActual = YAML.load((await fs.readFile(kcPath)).toString('utf-8')) as {
users: { name: string; user: { token: string } }[];
contexts: {
context: { cluster: string; user: string; namespace: string };
name: string;
}[];
'current-context': string;
clusters: object[];
};

const currentCtx = kcu.getCurrentContext();
const currentCtxObj = kcActual.contexts.find(ctx => ctx.name === currentCtx);
const sandboxUser = currentCtxObj.context.user;
const sandboxUserObj = kcActual.users.find(user => user.name === sandboxUser);

const secrets = await Oc.Instance.getKubernetesObjects('Secret');
const pipelineTokenSecret = secrets.find((secret) => secret.metadata.name.startsWith('pipeline-token')) as any;
const pipelineToken = Buffer.from(pipelineTokenSecret.data.token, 'base64').toString();

sandboxUserObj.user = {
token: pipelineToken
}

await fs.writeFile(kcPath, YAML.dump(kcActual, { lineWidth: Number.POSITIVE_INFINITY }));
}

static async loginUsingClipboardInfo(dashboardUrl: string): Promise<string | null> {
const clipboard = await Cluster.readFromClipboard();
if (!NameValidator.ocLoginCommandMatches(clipboard)) {
Expand All @@ -899,4 +940,9 @@ export class Cluster extends OpenShiftItem {
await commands.executeCommand('setContext', 'isLoggedIn', true);
return `Successfully logged in to '${clusterURL}'`;
}

static isOpenShiftSandbox(url :string): boolean {
const asUrl = new URL(url);
return asUrl.hostname.endsWith('openshiftapps.com');
}
}

0 comments on commit eb06f1c

Please sign in to comment.