1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Working POC against DECC

For the demo to work the following env vars need to passed when running lens in dev
mode:

- DECC_URL: This is the DECC Manager URL
- DECC_USERNAME: This is the username you would use against keycloak
- DECC_PASSWORD: This is the password you would use against keycloak
- NODE_ENV: Should be set to `development`
This commit is contained in:
Steve Richards 2020-09-24 15:14:26 +01:00
parent 9c2c6b1c71
commit 48c712da32
3 changed files with 82 additions and 18 deletions

View File

@ -6,7 +6,7 @@ import { Cluster } from "./cluster"
import logger from "./logger"; import logger from "./logger";
import { apiKubePrefix } from "../common/vars"; import { apiKubePrefix } from "../common/vars";
import { workspaceStore, Workspace } from "../common/workspace-store"; import { workspaceStore, Workspace } from "../common/workspace-store";
import { userStore } from "../common/user-store"; import { userStore, UserStore } from "../common/user-store";
import * as request from "request-promise-native"; import * as request from "request-promise-native";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import {kubeconfig} from '../common/utils/k8sTemplates'; import {kubeconfig} from '../common/utils/k8sTemplates';
@ -15,6 +15,7 @@ import { readFile } from "fs-extra"
import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers" import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers"
import { customRequestPromise } from "../common/request"; import { customRequestPromise } from "../common/request";
import orderBy from "lodash/orderBy"; import orderBy from "lodash/orderBy";
import queryString from 'query-string';
const ignoredDECCNamespaces = [ const ignoredDECCNamespaces = [
'kube-system', 'kube-public', 'openstack-provider-system', 'system', 'kube-system', 'kube-public', 'openstack-provider-system', 'system',
@ -53,6 +54,31 @@ export class DECCManager {
return res.body; return res.body;
} }
async getK8sToken(): Promise<[]> {
const headers = {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
};
const res = await customRequestPromise({
uri: `http://${process.env.DECC_URL}/auth/realms/iam/protocol/openid-connect/token`,
headers: headers,
method: 'POST', body: queryString.stringify({
grant_type: 'password',
response_type: 'id_token',
scope: 'openid',
client_id: 'k8s',
username: `${process.env.DECC_USERNAME}`,
password: `${process.env.DECC_PASSWORD}`,
}),
json: true,
resolveWithFullResponse: true,
timeout: 10000,
});
// logger.info(`getTokenForCluster: res - ${JSON.stringify(res)}`);
return res.body;
}
async getDECCNamespaces() { async getDECCNamespaces() {
try { try {
const res = await this.getNamespaces(); const res = await this.getNamespaces();
@ -99,6 +125,15 @@ export class DECCManager {
} }
} }
async getK8sTokenForUser() {
try {
const res = await this.getK8sToken();
return res;
} catch(err) {
logger.error(`getK8sTokenForUser: ${String(err)}`);
}
}
addLensDECCWorkspace(ws: string) { addLensDECCWorkspace(ws: string) {
const wsPrefix = `decc`; const wsPrefix = `decc`;
@ -108,7 +143,7 @@ export class DECCManager {
} }
} }
addLensClusterToDECCWorkspace(deccCluster, idToken: string, refreshToken: string, username: string, workspace: Workspace) { addLensClusterToDECCWorkspace(deccCluster, idToken: string, refreshToken: string, username: string, workspace: Workspace, k8sToken) {
// check if cluster is already in the cluster store // check if cluster is already in the cluster store
var clusterPresent = false; var clusterPresent = false;
const clusterPrefix = `decc` const clusterPrefix = `decc`
@ -123,6 +158,15 @@ export class DECCManager {
let ucpDashboard = `https://${deccCluster.status.providerStatus.ucpDashboard.split(":", 2).reverse()[0].substring(2)}:443`; let ucpDashboard = `https://${deccCluster.status.providerStatus.ucpDashboard.split(":", 2).reverse()[0].substring(2)}:443`;
//logger.info(`addLensClusterToDECCWorkspace: ucpDashboard - ${ucpDashboard}`); //logger.info(`addLensClusterToDECCWorkspace: ucpDashboard - ${ucpDashboard}`);
//let clusterToken = this.getTokenForCluster(deccCluster.metadata.uid);
//logger.info(`addLensClusterToDECCWorkspace: clusterToken - ${clusterToken}`);
// let parsedClusterIdToken = userStore.decodeToken(k8sToken["id_token"]);
// logger.info(`addLensClusterToDECCWorkspace: parsedClusterToken - ${parsedClusterIdToken}`);
const idTokenToUse = `${clusterPrefix}-${deccCluster.metadata.name}` === "decc-kaas-mgmt" ? idToken : k8sToken["id_token"]
const refreshTokenToUse = `${clusterPrefix}-${deccCluster.metadata.name}` === "decc-kaas-mgmt" ? refreshToken : k8sToken["refresh_token"]
const jsConfig = kubeconfig({ const jsConfig = kubeconfig({
username: username, username: username,
clusterName: `${clusterPrefix}-${deccCluster.metadata.name}`, clusterName: `${clusterPrefix}-${deccCluster.metadata.name}`,
@ -131,8 +175,8 @@ export class DECCManager {
idpIssuerUrl: deccCluster.status.providerStatus.oidc.issuerUrl, idpIssuerUrl: deccCluster.status.providerStatus.oidc.issuerUrl,
server: ucpDashboard, server: ucpDashboard,
apiCertificate: deccCluster.status.providerStatus.apiServerCertificate, apiCertificate: deccCluster.status.providerStatus.apiServerCertificate,
idToken: idToken, idToken: idTokenToUse,
refreshToken: refreshToken refreshToken: refreshTokenToUse
}); });
//console.log(`Generated kubeconfig: ${YAML.stringify(jsConfig)}`) //console.log(`Generated kubeconfig: ${YAML.stringify(jsConfig)}`)
@ -162,14 +206,14 @@ export class DECCManager {
}; };
} }
addLensClustersToDECCWorkspace(deccClusters, idToken: string, refreshToken: string, username: string, wsName: string) { addLensClustersToDECCWorkspace(deccClusters, idToken: string, refreshToken: string, username: string, wsName: string, k8sToken) {
const wsPrefix = `decc`; const wsPrefix = `decc`;
const workspace = workspaceStore.getByName(`${wsPrefix}-${wsName}`); const workspace = workspaceStore.getByName(`${wsPrefix}-${wsName}`);
//logger.info(`addLensClustersToDECCWorkspace: Processing clusters in Workspace ${workspace.name} for User ${username}`); //logger.info(`addLensClustersToDECCWorkspace: Processing clusters in Workspace ${workspace.name} for User ${username}`);
deccClusters.forEach(cluster => { deccClusters.forEach(cluster => {
this.addLensClusterToDECCWorkspace(cluster, idToken, refreshToken, username, workspace) this.addLensClusterToDECCWorkspace(cluster, idToken, refreshToken, username, workspace, k8sToken)
}); });
} }
@ -198,7 +242,7 @@ export class DECCManager {
}); });
} }
refreshLensDECCClusterKubeconfigs(idToken:string , refreshToken: string, username: string, workspace: string) { refreshLensDECCClusterKubeconfigs(idToken:string , refreshToken: string, username: string, workspace: string, k8sToken) {
//logger.info(`refreshLensDECCClusterKubeconfigs: Processing Workspace Name ${workspace}`); //logger.info(`refreshLensDECCClusterKubeconfigs: Processing Workspace Name ${workspace}`);
const wsPrefix = `decc`; const wsPrefix = `decc`;
const ws = workspaceStore.getByName(`${wsPrefix}-${workspace}`); const ws = workspaceStore.getByName(`${wsPrefix}-${workspace}`);
@ -207,6 +251,8 @@ export class DECCManager {
//logger.info(`refreshLensDECCClusterKubeconfigs: Processing Workspace ${JSON.stringify(ws)}`) //logger.info(`refreshLensDECCClusterKubeconfigs: Processing Workspace ${JSON.stringify(ws)}`)
clusterStore.getByWorkspaceId(ws.id).forEach(cluster => { clusterStore.getByWorkspaceId(ws.id).forEach(cluster => {
const idTokenToUse = cluster.preferences.clusterName === "decc-kaas-mgmt" ? idToken : k8sToken["id_token"]
const refreshTokenToUse = cluster.preferences.clusterName === "decc-kaas-mgmt" ? refreshToken : k8sToken["refresh_token"]
const currentKubeConfig = loadConfig(cluster.kubeConfigPath); //readFile(cluster.kubeConfigPath, "utf8"); const currentKubeConfig = loadConfig(cluster.kubeConfigPath); //readFile(cluster.kubeConfigPath, "utf8");
// console.log(`refreshClusterKubeConfigs: Read kubeconfig from file: ${cluster.kubeConfigPath}. Contents: ${YAML.stringify(kubeConfig)}`); // console.log(`refreshClusterKubeConfigs: Read kubeconfig from file: ${cluster.kubeConfigPath}. Contents: ${YAML.stringify(kubeConfig)}`);
// console.log(`refreshClusterKubeConfigs: kubeconfig users[0]: ${YAML.stringify(kubeConfig.users[0])}`); // console.log(`refreshClusterKubeConfigs: kubeconfig users[0]: ${YAML.stringify(kubeConfig.users[0])}`);
@ -220,10 +266,11 @@ export class DECCManager {
idpIssuerUrl: currentKubeConfig.users[0].authProvider.config["idp-issuer-url"], idpIssuerUrl: currentKubeConfig.users[0].authProvider.config["idp-issuer-url"],
server: currentKubeConfig.clusters[0].server, server: currentKubeConfig.clusters[0].server,
apiCertificate: currentKubeConfig.clusters[0].caData, apiCertificate: currentKubeConfig.clusters[0].caData,
idToken: idToken, idToken: idTokenToUse,
refreshToken: refreshToken refreshToken: refreshTokenToUse
}); });
cluster.contextName = `${username}@${currentKubeConfig.clusters[0].name}`;
ClusterStore.embedCustomKubeConfig(cluster.id, YAML.stringify(jsConfig)); ClusterStore.embedCustomKubeConfig(cluster.id, YAML.stringify(jsConfig));
logger.info(`refreshLensDECCClusterKubeconfigs: Updated Cluster ${cluster.preferences.clusterName} kubeconfig with new token values`); logger.info(`refreshLensDECCClusterKubeconfigs: Updated Cluster ${cluster.preferences.clusterName} kubeconfig with new token values`);
cluster.refresh(); cluster.refresh();
@ -237,6 +284,9 @@ export class DECCManager {
const username = parsedIdToken.preferred_username; const username = parsedIdToken.preferred_username;
const userIAMRoles = parsedIdToken.iam_roles; const userIAMRoles = parsedIdToken.iam_roles;
// get the token from the k8s client for this user
const k8sToken = await this.getK8sTokenForUser();
// get all available DECC Namespaces // get all available DECC Namespaces
const deccNamespaces = await this.getDECCNamespaces(); const deccNamespaces = await this.getDECCNamespaces();
// logger.info(`createDECCLensEnv: The following namespaces exist in DECC - ${deccNamespaces.toString()}`); // logger.info(`createDECCLensEnv: The following namespaces exist in DECC - ${deccNamespaces.toString()}`);
@ -256,13 +306,13 @@ export class DECCManager {
//logger.info(`createDECCLensEnv: The following clusters exist in Namespace ${ns} - ${JSON.stringify(deccClustersByNamespace)}`); //logger.info(`createDECCLensEnv: The following clusters exist in Namespace ${ns} - ${JSON.stringify(deccClustersByNamespace)}`);
// refresh tokens for any existing clusters // refresh tokens for any existing clusters
this.refreshLensDECCClusterKubeconfigs(idToken, refreshToken, username, ns); this.refreshLensDECCClusterKubeconfigs(idToken, refreshToken, username, ns, k8sToken);
// now lets add the workspace in Lens // now lets add the workspace in Lens
this.addLensDECCWorkspace(ns); this.addLensDECCWorkspace(ns);
// now lets add the clusters to the workspace // now lets add the clusters to the workspace
this.addLensClustersToDECCWorkspace(deccClustersByNamespace, idToken, refreshToken, username, ns); this.addLensClustersToDECCWorkspace(deccClustersByNamespace, idToken, refreshToken, username, ns, k8sToken);
} catch (err) { } catch (err) {
logger.error(`createDECCLensEnv: ${String(err)}`); logger.error(`createDECCLensEnv: ${String(err)}`);

View File

@ -134,6 +134,7 @@ export class LensProxy {
protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) { protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) {
const cluster = this.clusterManager.getClusterForRequest(req) const cluster = this.clusterManager.getClusterForRequest(req)
if (cluster) { if (cluster) {
try {
await cluster.contextHandler.ensureServer(); await cluster.contextHandler.ensureServer();
const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler) const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler)
if (proxyTarget) { if (proxyTarget) {
@ -141,6 +142,9 @@ export class LensProxy {
res.setHeader("Access-Control-Allow-Origin", this.origin); res.setHeader("Access-Control-Allow-Origin", this.origin);
return proxy.web(req, res, proxyTarget); return proxy.web(req, res, proxyTarget);
} }
} catch (err) {
logger.error(`[lens-proxy] handleRequest: ${String(err)}`);
}
} }
this.router.route(cluster, req, res); this.router.route(cluster, req, res);
} }

View File

@ -3,6 +3,7 @@
<script src="https://a69adcd0687194b2b8adebdbe93f2a02-977850409.eu-west-2.elb.amazonaws.com/auth/js/keycloak.js"></script> <script src="https://a69adcd0687194b2b8adebdbe93f2a02-977850409.eu-west-2.elb.amazonaws.com/auth/js/keycloak.js"></script>
<script> <script>
const { ipcRenderer } = require('electron') const { ipcRenderer } = require('electron')
const useK8sClientId = new URL(location.href).searchParams.get('k8s');
var keycloak = new Keycloak({ var keycloak = new Keycloak({
url: 'https://a69adcd0687194b2b8adebdbe93f2a02-977850409.eu-west-2.elb.amazonaws.com/auth', url: 'https://a69adcd0687194b2b8adebdbe93f2a02-977850409.eu-west-2.elb.amazonaws.com/auth',
@ -11,13 +12,22 @@ var keycloak = new Keycloak({
scope: 'offline_access openid', scope: 'offline_access openid',
}); });
var keycloakOptions = {
flow: 'standard',
enableLogging: true,
useNonce: false,
onLoad: 'login-required',
checkLoginIframe: false,
redirectUri: 'http://localhost:3000'
}
//if param "logout" was passed to this page, logout user! //if param "logout" was passed to this page, logout user!
const logoutUser = new URL(location.href).searchParams.get('logout'); const logoutUser = new URL(location.href).searchParams.get('logout');
if(logoutUser){ if(logoutUser){
keycloak.init(); keycloak.init();
keycloak.logout({redirectUri: 'http://localhost:3000'}); keycloak.logout({redirectUri: 'http://localhost:3000'});
}else{ }else{
keycloak.init({ flow: 'standard', enableLogging: true, useNonce: false, onLoad: 'login-required', checkLoginIframe: false, redirectUri: 'http://localhost:3000'}).success(function(authenticated) { keycloak.init(keycloakOptions).success(function(authenticated) {
console.log('success!!'); console.log('success!!');
if (authenticated) { if (authenticated) {
console.log("keycloak.token: " + keycloak.token); console.log("keycloak.token: " + keycloak.token);