diff --git a/package.json b/package.json index 70230c3268..8bb1f54ea9 100644 --- a/package.json +++ b/package.json @@ -204,6 +204,7 @@ "react-router": "^5.2.0", "request": "^2.88.2", "request-promise-native": "^1.0.8", + "selfsigned": "^1.10.8", "semver": "^7.3.2", "serializr": "^2.0.3", "shell-env": "^3.0.0", diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 12acb793ab..caca7be4e0 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -14,6 +14,7 @@ import { getFeatures, installFeature, uninstallFeature, upgradeFeature } from ". import request, { RequestPromiseOptions } from "request-promise-native" import { apiResources } from "../common/rbac"; import logger from "./logger" +import { getProxyCertificate } from "./lens-proxy-cert"; export enum ClusterStatus { AccessGranted = 2, @@ -93,7 +94,7 @@ export class Cluster implements ClusterModel { try { this.contextHandler = new ContextHandler(this); this.kubeconfigManager = new KubeconfigManager(this, this.contextHandler, port); - this.kubeProxyUrl = `http://localhost:${port}${apiKubePrefix}`; + this.kubeProxyUrl = `https://localhost:${port}${apiKubePrefix}`; this.initialized = true; logger.info(`[CLUSTER]: "${this.contextName}" init success`, { id: this.id, @@ -234,6 +235,7 @@ export class Cluster implements ClusterModel { return request(apiUrl, { json: true, timeout: 5000, + strictSSL: false, // TODO: use proxy CA ...options, headers: { Host: `${this.id}.${new URL(this.kubeProxyUrl).host}`, // required in ClusterManager.getClusterForRequest() diff --git a/src/main/index.ts b/src/main/index.ts index e4fd246467..f416607095 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -18,6 +18,7 @@ import { userStore } from "../common/user-store"; import { workspaceStore } from "../common/workspace-store"; import { tracker } from "../common/tracker"; import logger from "./logger" +import { getProxyCertificate } from "./lens-proxy-cert"; const workingDir = path.join(app.getPath("appData"), appName); app.setName(appName); @@ -73,6 +74,15 @@ async function main() { app.quit(); } + const proxyCert = getProxyCertificate() + app.on("certificate-error", (event: Electron.Event, webContents: Electron.WebContents, url: string, error: string, certificate: Electron.Certificate, callback: (isTrusted: boolean) => void) => { + if (certificate.data.trim().replace(/(?:\r\n)/g, "\n") === proxyCert.cert.trim().replace(/(?:\r\n)/g, "\n")) { + callback(true) + } else { + callback(false) + } + }) + // create window manager and open app windowManager = new WindowManager(proxyPort); } diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index 33521fdcf5..4e7c76d70f 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -31,6 +31,7 @@ export class KubeAuthProxy { return; } const proxyBin = await this.kubectl.getPath() + logger.info(proxyBin) const args = [ "proxy", "-p", `${this.port}`, diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index 59a47c3fbc..6a39d8b15a 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -6,6 +6,7 @@ import path from "path" import fs from "fs-extra" import { dumpConfigYaml, loadConfig } from "../common/kube-helpers" import logger from "./logger" +import { getProxyCertificate } from "./lens-proxy-cert"; export class KubeconfigManager { protected configDir = app.getPath("temp") @@ -29,7 +30,7 @@ export class KubeconfigManager { } protected resolveProxyUrl() { - return `http://127.0.0.1:${this.port}/${this.cluster.id}` + return `https://127.0.0.1:${this.port}/${this.cluster.id}` } /** @@ -47,11 +48,11 @@ export class KubeconfigManager { { name: contextName, server: this.resolveProxyUrl(), - skipTLSVerify: undefined, + skipTLSVerify: true } ], users: [ - { name: "proxy" }, + { name: "proxy", username: "lens", password: "lens" }, ], contexts: [ { diff --git a/src/main/lens-proxy-cert.ts b/src/main/lens-proxy-cert.ts new file mode 100644 index 0000000000..0aea4dcf47 --- /dev/null +++ b/src/main/lens-proxy-cert.ts @@ -0,0 +1,27 @@ +import * as path from "path" +import * as fs from "fs" +import * as selfsigned from "selfsigned" +import logger from "./logger" + +export type SelfSignedCert = { + private: string; + public: string; + cert: string; +} + +let selfSignedCertificate: SelfSignedCert = null + +export function getProxyCertificate(): SelfSignedCert { + if (selfSignedCertificate == null) { + const attrs = [{ name: "commonName", value: "localhost"}] + selfSignedCertificate = selfsigned.generate(attrs, { + keySize: 2048, + algorithm: "sha256", + days: 365, + extensions: [{ name: 'basicConstraints', cA: true }] + }) as SelfSignedCert + console.log(selfSignedCertificate) + } + + return selfSignedCertificate +} diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index dfb7de7867..77172e31e6 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -10,6 +10,7 @@ import { Router } from "./router" import { ClusterManager } from "./cluster-manager" import { ContextHandler } from "./context-handler"; import logger from "./logger" +import { getProxyCertificate } from "./lens-proxy-cert"; export class LensProxy { protected origin: string @@ -23,7 +24,7 @@ export class LensProxy { } private constructor(protected port: number, protected clusterManager: ClusterManager) { - this.origin = `http://localhost:${port}` + this.origin = `https://localhost:${port}` this.router = new Router(); } @@ -41,9 +42,12 @@ export class LensProxy { protected buildCustomProxy(): http.Server { const proxy = this.createProxy(); + const proxyCert = getProxyCertificate() const spdyProxy = spdy.createServer({ + key: proxyCert.private, + cert: proxyCert.cert, spdy: { - plain: true, + plain: false, protocols: ["http/1.1", "spdy/3.1"] } }, (req: http.IncomingMessage, res: http.ServerResponse) => { diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 348d5bbd3f..dbc0dd8e0d 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -71,7 +71,7 @@ export class WindowManager { async showMain() { try { await this.showSplash(); - await this.mainView.loadURL(`http://localhost:${this.proxyPort}`) + await this.mainView.loadURL(`https://localhost:${this.proxyPort}`) this.mainView.show(); this.splashWindow.close(); } catch (err) { diff --git a/types/mocks.d.ts b/types/mocks.d.ts index 7ddd25267b..6467c85f4e 100644 --- a/types/mocks.d.ts +++ b/types/mocks.d.ts @@ -3,6 +3,7 @@ declare module "mac-ca" declare module "win-ca" declare module "@hapi/call" declare module "@hapi/subtext" +declare module "selfsigned" // Global path to static assets declare const __static: string; diff --git a/yarn.lock b/yarn.lock index 300efc58ce..0cb2101860 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8297,6 +8297,11 @@ node-abi@^2.11.0: dependencies: semver "^5.4.1" +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + node-forge@^0.7.5: version "0.7.6" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" @@ -10321,6 +10326,13 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= +selfsigned@^1.10.8: + version "1.10.8" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.8.tgz#0d17208b7d12c33f8eac85c41835f27fc3d81a30" + integrity sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w== + dependencies: + node-forge "^0.10.0" + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"