mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
TLS cert per cluster for lens-k8s-proxy (#5081)
Co-authored-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
477814f1e0
commit
b3574e1a21
@ -44,7 +44,7 @@
|
|||||||
"postversion": "git push --set-upstream ${GIT_REMOTE:-origin} release/v$npm_package_version"
|
"postversion": "git push --set-upstream ${GIT_REMOTE:-origin} release/v$npm_package_version"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"k8sProxyVersion": "0.1.5",
|
"k8sProxyVersion": "0.2.1",
|
||||||
"bundledKubectlVersion": "1.23.3",
|
"bundledKubectlVersion": "1.23.3",
|
||||||
"bundledHelmVersion": "3.7.2",
|
"bundledHelmVersion": "3.7.2",
|
||||||
"sentryDsn": ""
|
"sentryDsn": ""
|
||||||
|
|||||||
@ -24,8 +24,6 @@ import { createClusterInjectionToken } from "../cluster/create-cluster-injection
|
|||||||
|
|
||||||
import directoryForUserDataInjectable
|
import directoryForUserDataInjectable
|
||||||
from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
import kubeAuthProxyCaInjectable from "../../main/kube-auth-proxy/kube-auth-proxy-ca.injectable";
|
|
||||||
import createKubeAuthProxyCertFilesInjectable from "../../main/kube-auth-proxy/create-kube-auth-proxy-cert-files.injectable";
|
|
||||||
|
|
||||||
console = new Console(stdout, stderr);
|
console = new Console(stdout, stderr);
|
||||||
|
|
||||||
@ -89,8 +87,6 @@ describe("cluster-store", () => {
|
|||||||
mainDi = dis.mainDi;
|
mainDi = dis.mainDi;
|
||||||
|
|
||||||
mainDi.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
mainDi.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||||
mainDi.override(createKubeAuthProxyCertFilesInjectable, () => ({} as any));
|
|
||||||
mainDi.override(kubeAuthProxyCaInjectable, () => ({} as any));
|
|
||||||
|
|
||||||
await dis.runSetups();
|
await dis.runSetups();
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import mockFs from "mock-fs";
|
|||||||
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../getDiForUnitTesting";
|
||||||
import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable";
|
import createContextHandlerInjectable from "../context-handler/create-context-handler.injectable";
|
||||||
import type { Cluster } from "../../common/cluster/cluster";
|
import type { Cluster } from "../../common/cluster/cluster";
|
||||||
import kubeAuthProxyCaInjectable from "../kube-auth-proxy/kube-auth-proxy-ca.injectable";
|
|
||||||
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||||
|
|
||||||
jest.mock("electron", () => ({
|
jest.mock("electron", () => ({
|
||||||
@ -83,7 +82,6 @@ describe("ContextHandler", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
di.override(createKubeAuthProxyInjectable, () => ({} as any));
|
di.override(createKubeAuthProxyInjectable, () => ({} as any));
|
||||||
di.override(kubeAuthProxyCaInjectable, () => ({} as any));
|
|
||||||
|
|
||||||
await di.runSetups();
|
await di.runSetups();
|
||||||
|
|
||||||
|
|||||||
@ -52,8 +52,6 @@ import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-p
|
|||||||
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import spawnInjectable from "../child-process/spawn.injectable";
|
import spawnInjectable from "../child-process/spawn.injectable";
|
||||||
import kubeAuthProxyCaInjectable from "../kube-auth-proxy/kube-auth-proxy-ca.injectable";
|
|
||||||
import createKubeAuthProxyCertFilesInjectable from "../kube-auth-proxy/create-kube-auth-proxy-cert-files.injectable";
|
|
||||||
|
|
||||||
console = new Console(stdout, stderr);
|
console = new Console(stdout, stderr);
|
||||||
|
|
||||||
@ -97,8 +95,6 @@ describe("kube auth proxy tests", () => {
|
|||||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||||
|
|
||||||
di.override(spawnInjectable, () => mockSpawn);
|
di.override(spawnInjectable, () => mockSpawn);
|
||||||
di.override(createKubeAuthProxyCertFilesInjectable, () => ({} as any));
|
|
||||||
di.override(kubeAuthProxyCaInjectable, () => ({} as any));
|
|
||||||
|
|
||||||
mockFs(mockMinikubeConfig);
|
mockFs(mockMinikubeConfig);
|
||||||
|
|
||||||
|
|||||||
@ -14,11 +14,8 @@ import { ClusterManager } from "../../cluster-manager";
|
|||||||
import clusterStoreInjectable from "../../../common/cluster-store/cluster-store.injectable";
|
import clusterStoreInjectable from "../../../common/cluster-store/cluster-store.injectable";
|
||||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||||
import { createClusterInjectionToken } from "../../../common/cluster/create-cluster-injection-token";
|
import { createClusterInjectionToken } from "../../../common/cluster/create-cluster-injection-token";
|
||||||
import directoryForKubeConfigsInjectable
|
import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||||
from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
import { ClusterStore } from "../../../common/cluster-store/cluster-store";
|
||||||
import kubeAuthProxyCaInjectable from "../../kube-auth-proxy/kube-auth-proxy-ca.injectable";
|
|
||||||
import createKubeAuthProxyCertFilesInjectable from "../../kube-auth-proxy/create-kube-auth-proxy-cert-files.injectable";
|
|
||||||
|
|
||||||
|
|
||||||
jest.mock("electron", () => ({
|
jest.mock("electron", () => ({
|
||||||
app: {
|
app: {
|
||||||
@ -42,9 +39,6 @@ describe("kubeconfig-sync.source tests", () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||||
|
|
||||||
di.override(kubeAuthProxyCaInjectable, () => Promise.resolve(Buffer.from("ca")));
|
|
||||||
di.override(createKubeAuthProxyCertFilesInjectable, () => ({} as any));
|
|
||||||
|
|
||||||
mockFs();
|
mockFs();
|
||||||
|
|
||||||
await di.runSetups();
|
await di.runSetups();
|
||||||
@ -62,6 +56,7 @@ describe("kubeconfig-sync.source tests", () => {
|
|||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
mockFs.restore();
|
mockFs.restore();
|
||||||
ClusterManager.resetInstance();
|
ClusterManager.resetInstance();
|
||||||
|
ClusterStore.resetInstance();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("configsToModels", () => {
|
describe("configsToModels", () => {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ interface PrometheusServicePreferences {
|
|||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
createKubeAuthProxy: CreateKubeAuthProxy;
|
createKubeAuthProxy: CreateKubeAuthProxy;
|
||||||
authProxyCa: Promise<Buffer>;
|
authProxyCa: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ContextHandler {
|
export class ContextHandler {
|
||||||
@ -123,7 +123,7 @@ export class ContextHandler {
|
|||||||
return `https://127.0.0.1:${this.kubeAuthProxy.port}${this.kubeAuthProxy.apiPrefix}${path}`;
|
return `https://127.0.0.1:${this.kubeAuthProxy.port}${this.kubeAuthProxy.apiPrefix}${path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async resolveAuthProxyCa() {
|
resolveAuthProxyCa() {
|
||||||
return this.dependencies.authProxyCa;
|
return this.dependencies.authProxyCa;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ export class ContextHandler {
|
|||||||
protected async newApiTarget(timeout: number): Promise<httpProxy.ServerOptions> {
|
protected async newApiTarget(timeout: number): Promise<httpProxy.ServerOptions> {
|
||||||
await this.ensureServer();
|
await this.ensureServer();
|
||||||
|
|
||||||
const caFileContents = await this.resolveAuthProxyCa();
|
const ca = this.dependencies.authProxyCa;
|
||||||
const clusterPath = this.clusterUrl.path !== "/" ? this.clusterUrl.path : "";
|
const clusterPath = this.clusterUrl.path !== "/" ? this.clusterUrl.path : "";
|
||||||
const apiPrefix = `${this.kubeAuthProxy.apiPrefix}${clusterPath}`;
|
const apiPrefix = `${this.kubeAuthProxy.apiPrefix}${clusterPath}`;
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ export class ContextHandler {
|
|||||||
host: "127.0.0.1",
|
host: "127.0.0.1",
|
||||||
port: this.kubeAuthProxy.port,
|
port: this.kubeAuthProxy.port,
|
||||||
path: apiPrefix,
|
path: apiPrefix,
|
||||||
ca: caFileContents.toString(),
|
ca,
|
||||||
},
|
},
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
timeout,
|
timeout,
|
||||||
|
|||||||
@ -3,23 +3,27 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import selfsigned from "selfsigned";
|
||||||
import type { Cluster } from "../../common/cluster/cluster";
|
import type { Cluster } from "../../common/cluster/cluster";
|
||||||
import { ContextHandler } from "./context-handler";
|
import { ContextHandler } from "./context-handler";
|
||||||
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable";
|
||||||
import kubeAuthProxyCaInjectable from "../kube-auth-proxy/kube-auth-proxy-ca.injectable";
|
import { getKubeAuthProxyCertificate } from "../kube-auth-proxy/get-kube-auth-proxy-certificate";
|
||||||
|
import URLParse from "url-parse";
|
||||||
|
|
||||||
const createContextHandlerInjectable = getInjectable({
|
const createContextHandlerInjectable = getInjectable({
|
||||||
id: "create-context-handler",
|
id: "create-context-handler",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const authProxyCa = di.inject(kubeAuthProxyCaInjectable);
|
return (cluster: Cluster) => {
|
||||||
|
const clusterUrl = new URLParse(cluster.apiUrl);
|
||||||
|
|
||||||
const dependencies = {
|
const dependencies = {
|
||||||
createKubeAuthProxy: di.inject(createKubeAuthProxyInjectable),
|
createKubeAuthProxy: di.inject(createKubeAuthProxyInjectable),
|
||||||
authProxyCa,
|
authProxyCa: getKubeAuthProxyCertificate(clusterUrl.hostname, selfsigned.generate).cert,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (cluster: Cluster) => new ContextHandler(dependencies, cluster);
|
return new ContextHandler(dependencies, cluster);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
|
||||||
import * as selfsigned from "selfsigned";
|
|
||||||
import { createKubeAuthProxyCertFiles } from "./create-kube-auth-proxy-cert-files";
|
|
||||||
import writeFileInjectable from "../../common/fs/write-file.injectable";
|
|
||||||
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
const createKubeAuthProxyCertFilesInjectable = getInjectable({
|
|
||||||
id: "create-kube-auth-proxy-cert-files",
|
|
||||||
|
|
||||||
instantiate: async (di) => {
|
|
||||||
const userData = di.inject(directoryForUserDataInjectable);
|
|
||||||
const certPath = path.join(userData, "kube-auth-proxy");
|
|
||||||
|
|
||||||
return createKubeAuthProxyCertFiles(certPath, {
|
|
||||||
generate: selfsigned.generate,
|
|
||||||
writeFile: di.inject(writeFileInjectable),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default createKubeAuthProxyCertFilesInjectable;
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import path from "path";
|
|
||||||
import type * as selfsigned from "selfsigned";
|
|
||||||
|
|
||||||
type SelfSignedGenerate = typeof selfsigned.generate;
|
|
||||||
|
|
||||||
interface CreateKubeAuthProxyCertificateFilesDependencies {
|
|
||||||
generate: SelfSignedGenerate;
|
|
||||||
writeFile: (path: string, content: string | Buffer) => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getKubeAuthProxyCertificate(generate: SelfSignedGenerate): selfsigned.SelfSignedCert {
|
|
||||||
const opts = [
|
|
||||||
{ name: "commonName", value: "Lens Certificate Authority" },
|
|
||||||
{ name: "organizationName", value: "Lens" },
|
|
||||||
];
|
|
||||||
|
|
||||||
return generate(opts, {
|
|
||||||
keySize: 2048,
|
|
||||||
algorithm: "sha256",
|
|
||||||
days: 365,
|
|
||||||
extensions: [
|
|
||||||
{ name: "basicConstraints", cA: true },
|
|
||||||
{ name: "subjectAltName", altNames: [
|
|
||||||
{ type: 2, value: "localhost" },
|
|
||||||
{ type: 7, ip: "127.0.0.1" },
|
|
||||||
] },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createKubeAuthProxyCertFiles(dir: string, dependencies: CreateKubeAuthProxyCertificateFilesDependencies): Promise<string> {
|
|
||||||
const cert = getKubeAuthProxyCertificate(dependencies.generate);
|
|
||||||
|
|
||||||
await dependencies.writeFile(path.join(dir, "proxy.key"), cert.private);
|
|
||||||
await dependencies.writeFile(path.join(dir, "proxy.crt"), cert.cert);
|
|
||||||
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
@ -6,10 +6,11 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import { KubeAuthProxy, KubeAuthProxyDependencies } from "./kube-auth-proxy";
|
import { KubeAuthProxy, KubeAuthProxyDependencies } from "./kube-auth-proxy";
|
||||||
import type { Cluster } from "../../common/cluster/cluster";
|
import type { Cluster } from "../../common/cluster/cluster";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import selfsigned from "selfsigned";
|
||||||
import { getBinaryName } from "../../common/vars";
|
import { getBinaryName } from "../../common/vars";
|
||||||
import directoryForBundledBinariesInjectable from "../../common/app-paths/directory-for-bundled-binaries/directory-for-bundled-binaries.injectable";
|
import directoryForBundledBinariesInjectable from "../../common/app-paths/directory-for-bundled-binaries/directory-for-bundled-binaries.injectable";
|
||||||
import spawnInjectable from "../child-process/spawn.injectable";
|
import spawnInjectable from "../child-process/spawn.injectable";
|
||||||
import createKubeAuthProxyCertFilesInjectable from "./create-kube-auth-proxy-cert-files.injectable";
|
import { getKubeAuthProxyCertificate } from "./get-kube-auth-proxy-certificate";
|
||||||
|
|
||||||
export type CreateKubeAuthProxy = (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => KubeAuthProxy;
|
export type CreateKubeAuthProxy = (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => KubeAuthProxy;
|
||||||
|
|
||||||
@ -18,15 +19,17 @@ const createKubeAuthProxyInjectable = getInjectable({
|
|||||||
|
|
||||||
instantiate: (di): CreateKubeAuthProxy => {
|
instantiate: (di): CreateKubeAuthProxy => {
|
||||||
const binaryName = getBinaryName("lens-k8s-proxy");
|
const binaryName = getBinaryName("lens-k8s-proxy");
|
||||||
|
|
||||||
|
return (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => {
|
||||||
|
const clusterUrl = new URL(cluster.apiUrl);
|
||||||
const dependencies: KubeAuthProxyDependencies = {
|
const dependencies: KubeAuthProxyDependencies = {
|
||||||
proxyBinPath: path.join(di.inject(directoryForBundledBinariesInjectable), binaryName),
|
proxyBinPath: path.join(di.inject(directoryForBundledBinariesInjectable), binaryName),
|
||||||
proxyCertPath: di.inject(createKubeAuthProxyCertFilesInjectable),
|
proxyCert: getKubeAuthProxyCertificate(clusterUrl.hostname, selfsigned.generate),
|
||||||
spawn: di.inject(spawnInjectable),
|
spawn: di.inject(spawnInjectable),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => (
|
return new KubeAuthProxy(dependencies, cluster, environmentVariables);
|
||||||
new KubeAuthProxy(dependencies, cluster, environmentVariables)
|
};
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
39
src/main/kube-auth-proxy/get-kube-auth-proxy-certificate.ts
Normal file
39
src/main/kube-auth-proxy/get-kube-auth-proxy-certificate.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type * as selfsigned from "selfsigned";
|
||||||
|
|
||||||
|
type SelfSignedGenerate = typeof selfsigned.generate;
|
||||||
|
|
||||||
|
const certCache: Map<string, selfsigned.SelfSignedCert> = new Map();
|
||||||
|
|
||||||
|
export function getKubeAuthProxyCertificate(hostname: string, generate: SelfSignedGenerate, useCache = true): selfsigned.SelfSignedCert {
|
||||||
|
if (useCache && certCache.has(hostname)) {
|
||||||
|
return certCache.get(hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
const opts = [
|
||||||
|
{ name: "commonName", value: "Lens Certificate Authority" },
|
||||||
|
{ name: "organizationName", value: "Lens" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const cert = generate(opts, {
|
||||||
|
keySize: 2048,
|
||||||
|
algorithm: "sha256",
|
||||||
|
days: 365,
|
||||||
|
extensions: [
|
||||||
|
{ name: "basicConstraints", cA: true },
|
||||||
|
{ name: "subjectAltName", altNames: [
|
||||||
|
{ type: 2, value: hostname },
|
||||||
|
{ type: 2, value: "localhost" },
|
||||||
|
{ type: 7, ip: "127.0.0.1" },
|
||||||
|
] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
certCache.set(hostname, cert);
|
||||||
|
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
|
||||||
import path from "path";
|
|
||||||
import readFileInjectable from "../../common/fs/read-file.injectable";
|
|
||||||
import createKubeAuthProxyCertFilesInjectable from "./create-kube-auth-proxy-cert-files.injectable";
|
|
||||||
|
|
||||||
const kubeAuthProxyCaInjectable = getInjectable({
|
|
||||||
id: "kube-auth-proxy-ca",
|
|
||||||
|
|
||||||
instantiate: async (di) => {
|
|
||||||
const certPath = await di.inject(createKubeAuthProxyCertFilesInjectable);
|
|
||||||
|
|
||||||
const readFile = di.inject(readFileInjectable);
|
|
||||||
|
|
||||||
return readFile(path.join(certPath, "proxy.crt"));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default kubeAuthProxyCaInjectable;
|
|
||||||
@ -10,12 +10,13 @@ import type { Cluster } from "../../common/cluster/cluster";
|
|||||||
import logger from "../logger";
|
import logger from "../logger";
|
||||||
import { getPortFrom } from "../utils/get-port";
|
import { getPortFrom } from "../utils/get-port";
|
||||||
import { makeObservable, observable, when } from "mobx";
|
import { makeObservable, observable, when } from "mobx";
|
||||||
|
import type { SelfSignedCert } from "selfsigned";
|
||||||
|
|
||||||
const startingServeRegex = /starting to serve on (?<address>.+)/i;
|
const startingServeRegex = /starting to serve on (?<address>.+)/i;
|
||||||
|
|
||||||
export interface KubeAuthProxyDependencies {
|
export interface KubeAuthProxyDependencies {
|
||||||
proxyBinPath: string;
|
proxyBinPath: string;
|
||||||
proxyCertPath: Promise<string>;
|
proxyCert: SelfSignedCert;
|
||||||
spawn: typeof spawn;
|
spawn: typeof spawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ export class KubeAuthProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const proxyBin = this.dependencies.proxyBinPath;
|
const proxyBin = this.dependencies.proxyBinPath;
|
||||||
const certPath = await this.dependencies.proxyCertPath;
|
const cert = this.dependencies.proxyCert;
|
||||||
|
|
||||||
this.proxyProcess = this.dependencies.spawn(proxyBin, [], {
|
this.proxyProcess = this.dependencies.spawn(proxyBin, [], {
|
||||||
env: {
|
env: {
|
||||||
@ -52,7 +53,8 @@ export class KubeAuthProxy {
|
|||||||
KUBECONFIG: this.cluster.kubeConfigPath,
|
KUBECONFIG: this.cluster.kubeConfigPath,
|
||||||
KUBECONFIG_CONTEXT: this.cluster.contextName,
|
KUBECONFIG_CONTEXT: this.cluster.contextName,
|
||||||
API_PREFIX: this.apiPrefix,
|
API_PREFIX: this.apiPrefix,
|
||||||
CERT_PATH: certPath,
|
PROXY_KEY: cert.private,
|
||||||
|
PROXY_CERT: cert.cert,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.proxyProcess.on("error", (error) => {
|
this.proxyProcess.on("error", (error) => {
|
||||||
|
|||||||
@ -57,8 +57,9 @@ const NonInjectedLogsDockTab = observer(({ className, tab, model, subscribeStore
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const overlay = document.querySelector(".PodLogs .list span.active");
|
const overlay = document.querySelector(".PodLogs .list span.active");
|
||||||
|
|
||||||
if (!overlay) return;
|
if (typeof overlay?.scrollIntoViewIfNeeded === "function") {
|
||||||
overlay.scrollIntoViewIfNeeded();
|
overlay.scrollIntoViewIfNeeded();
|
||||||
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,9 @@ export class Tab extends React.PureComponent<TabProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scrollIntoView() {
|
scrollIntoView() {
|
||||||
this.ref.current?.scrollIntoViewIfNeeded();
|
if (typeof this.ref.current?.scrollIntoViewIfNeeded === "function") {
|
||||||
|
this.ref.current.scrollIntoViewIfNeeded();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@boundMethod
|
@boundMethod
|
||||||
|
|||||||
2
types/dom.d.ts
vendored
2
types/dom.d.ts
vendored
@ -6,7 +6,7 @@ export {};
|
|||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Element {
|
interface Element {
|
||||||
scrollIntoViewIfNeeded(opt_center?: boolean): void;
|
scrollIntoViewIfNeeded?(opt_center?: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user