Skip to content
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

feat: Backport: Deprecate 'self-signed-cert' flag and implement autodetection for it #745

Merged
merged 1 commit into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,12 +338,11 @@ OPTIONS
-s, --tls
Enable TLS encryption.
Note, this option is turned on by default.
For Kubernetes infrastructure, it is required to provide own certificate: 'che-tls' secret with
TLS certificate must be pre-created in the configured namespace.
The only exception is Helm installer. In that case the secret will be generated automatically.
To provide own certificate for Kubernetes infrastructure, 'che-tls' secret with TLS certificate
must be pre-created in the configured namespace.
In case of providing own self-signed certificate 'self-signed-certificate' secret should be
also created.
For OpenShift, router will use default cluster certificates.
If the certificate is self-signed, '--self-signed-cert' option should be provided, otherwise
Che won't be able to start.
Please see docs for more details:
https://www.eclipse.org/che/docs/che-7/installing-che-in-tls-mode-with-self-signed-certificates/

Expand Down Expand Up @@ -414,10 +413,7 @@ OPTIONS
persistent volume storage class name to use to store Eclipse Che postgres database

--self-signed-cert
Authorize usage of self signed certificates for encryption.
This is the flag for Eclipse Che to propagate the certificate to components, so they will trust
it.
Note that `che-tls` secret with CA certificate must be created in the configured namespace.
Deprecated. The flag is ignored. Self signed certificates usage is autodetected now.

--skip-cluster-availability-check
Skip cluster availability check. The check is a simple request to ensure the cluster is reachable.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
"cli-ux": "^5.4.5",
"command-exists": "^1.2.8",
"debug": "^4.1.1",
"eclipse-che": "git://github.com/eclipse/che#7.14.2",
"eclipse-che": "git://github.com/eclipse/che#7.14.x",
"eclipse-che-minishift": "git://github.com/minishift/minishift#master",
"eclipse-che-operator": "git://github.com/eclipse/che-operator#7.14.2",
"eclipse-che-operator": "git://github.com/eclipse/che-operator#7.14.x",
"esprima": "^4.0.1",
"execa": "^4.0.0",
"fancy-test": "^1.4.7",
Expand Down
12 changes: 9 additions & 3 deletions src/api/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,19 @@ export class CheHelper {
}
}

async isSelfSignedCertificateSecretExist(namespace: string): Promise<boolean> {
const selfSignedCertSecret = await this.kube.getSecret(CHE_ROOT_CA_SECRET_NAME, namespace)
return !!selfSignedCertSecret
}

/**
* Gets self-signed Che CA certificate from 'self-signed-certificate' secret. The secret should exist.
* Gets self-signed Che CA certificate from 'self-signed-certificate' secret.
* If secret doesn't exist, undefined is returned.
*/
async retrieveCheCaCert(cheNamespace: string): Promise<string> {
async retrieveCheCaCert(cheNamespace: string): Promise<string | undefined> {
const cheCaSecret = await this.kube.getSecret(CHE_ROOT_CA_SECRET_NAME, cheNamespace)
if (!cheCaSecret) {
throw new Error('Che CA self-signed certificate not found. Are you using self-signed certificate?')
return
}

if (cheCaSecret.data && cheCaSecret.data['ca.crt']) {
Expand Down
21 changes: 20 additions & 1 deletion src/api/kube.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,6 @@ export class KubeHelper {
yamlCr.spec.k8s.tlsSecretName = 'che-tls'
}
}
yamlCr.spec.server.selfSignedCert = flags['self-signed-cert']
if (flags.domain) {
yamlCr.spec.k8s.ingressDomain = flags.domain
}
Expand Down Expand Up @@ -1794,6 +1793,26 @@ export class KubeHelper {
}
}

/**
* Creates a secret with given name and data.
* Data should not be base64 encoded.
*/
async createSecret(name: string, data: {[key: string]: string}, namespace: string): Promise<V1Secret | undefined> {
const k8sCoreApi = KubeHelper.KUBE_CONFIG.makeApiClient(CoreV1Api)

const secret = new V1Secret()
secret.metadata = new V1ObjectMeta()
secret.metadata.name = name
secret.metadata.namespace = namespace
secret.stringData = data

try {
return (await k8sCoreApi.createNamespacedSecret(namespace, secret)).body
} catch {
return
}
}

/**
* Awaits secret to be present and contain non-empty data fields specified in dataKeys parameter.
*/
Expand Down
8 changes: 6 additions & 2 deletions src/commands/cacert/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ export default class Export extends Command {
try {
await tasks.run(ctx)
const cheCaCert = await cheHelper.retrieveCheCaCert(flags.chenamespace)
const targetFile = await cheHelper.saveCheCaCert(cheCaCert, this.getTargetFile(flags.destination))
this.log(`Eclipse Che self-signed CA certificate is exported to ${targetFile}`)
if (cheCaCert) {
const targetFile = await cheHelper.saveCheCaCert(cheCaCert, this.getTargetFile(flags.destination))
this.log(`Eclipse Che self-signed CA certificate is exported to ${targetFile}`)
} else {
this.log('Seems commonly trusted certificate is used.')
}
} catch (error) {
this.error(error)
}
Expand Down
14 changes: 7 additions & 7 deletions src/commands/server/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,13 @@ export default class Start extends Command {
char: 's',
description: `Enable TLS encryption.
Note, this option is turned on by default.
For Kubernetes infrastructure, it is required to provide own certificate: 'che-tls' secret with TLS certificate must be pre-created in the configured namespace.
The only exception is Helm installer. In that case the secret will be generated automatically.
To provide own certificate for Kubernetes infrastructure, 'che-tls' secret with TLS certificate must be pre-created in the configured namespace.
In case of providing own self-signed certificate 'self-signed-certificate' secret should be also created.
For OpenShift, router will use default cluster certificates.
If the certificate is self-signed, '--self-signed-cert' option should be provided, otherwise Che won't be able to start.
Please see docs for more details: ${DOCS_LINK_INSTALL_TLS_WITH_SELF_SIGNED_CERT}`
}),
'self-signed-cert': flags.boolean({
description: `Authorize usage of self signed certificates for encryption.
This is the flag for Eclipse Che to propagate the certificate to components, so they will trust it.
Note that \`che-tls\` secret with CA certificate must be created in the configured namespace.`,
description: 'Deprecated. The flag is ignored. Self signed certificates usage is autodetected now.',
default: false
}),
platform: string({
Expand Down Expand Up @@ -253,7 +250,6 @@ export default class Start extends Command {
flags['devfile-registry-url'] && ignoredFlags.push('--devfile-registry-url')
flags['postgres-pvc-storage-class-name'] && ignoredFlags.push('--postgres-pvc-storage-class-name')
flags['workspace-pvc-storage-class-name'] && ignoredFlags.push('--workspace-pvc-storage-class-name')
flags['self-signed-cert'] && ignoredFlags.push('--self-signed-cert')
flags['os-oauth'] && ignoredFlags.push('--os-oauth')
flags.tls && ignoredFlags.push('--tls')
flags.cheimage && ignoredFlags.push('--cheimage')
Expand Down Expand Up @@ -327,6 +323,10 @@ export default class Start extends Command {
// Holds messages which should be printed at the end of chectl log
ctx.highlightedMessages = [] as string[]

if (flags['self-signed-cert']) {
this.warn('"self-signed-cert" flag is deprecated and has no effect. Autodetection is used instead.')
}

const cheTasks = new CheTasks(flags)
const platformTasks = new PlatformTasks()
const installerTasks = new InstallerTasks()
Expand Down
5 changes: 4 additions & 1 deletion src/tasks/component-installers/cert-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import * as path from 'path'

import { CheHelper } from '../../api/che'
import { KubeHelper } from '../../api/kube'
import { CA_CERT_GENERATION_JOB_IMAGE, CERT_MANAGER_NAMESPACE_NAME, CHE_TLS_SECRET_NAME } from '../../constants'
import { CA_CERT_GENERATION_JOB_IMAGE, CERT_MANAGER_NAMESPACE_NAME, CHE_ROOT_CA_SECRET_NAME, CHE_TLS_SECRET_NAME } from '../../constants'
import { base64Decode } from '../../util'
import { getMessageImportCaCertIntoBrowser } from '../installers/common-tasks'

Expand Down Expand Up @@ -171,6 +171,9 @@ export class CertManagerTasks {
const cheCaCrt = base64Decode(cheSecret.data['ca.crt'])
const cheCaCertPath = await this.cheHelper.saveCheCaCert(cheCaCrt)

// We need to put self-signed CA certificate seprately into CHE_ROOT_CA_SECRET_NAME secret
await this.kubeHelper.createSecret(CHE_ROOT_CA_SECRET_NAME, { 'ca.crt': cheCaCrt }, flags.chenamespace)

ctx.highlightedMessages.push(getMessageImportCaCertIntoBrowser(cheCaCertPath))
task.title = `${task.title}... is exported to ${cheCaCertPath}`
} else {
Expand Down
48 changes: 9 additions & 39 deletions src/tasks/installers/common-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
**********************************************************************/

import ansi = require('ansi-colors')
import { cli } from 'cli-ux'
import * as execa from 'execa'
import { copy, mkdirp, remove } from 'fs-extra'
import * as Listr from 'listr'
Expand Down Expand Up @@ -99,52 +98,23 @@ export function createEclipseCheCluster(flags: any, kube: KubeHelper): Listr.Lis
}
}

export function checkTlsCertificate(flags: any): Listr.ListrTask {
return {
title: 'Checking certificate',
// It makes sense to check whether self-signed certificate is used only if TLS mode is on
enabled: () => flags.tls,
// If the flag is set no need to check if it is required
skip: () => flags['self-signed-cert'],
task: async (_: any, task: any) => {
const warningMessage = 'Self-signed certificate is used, so "--self-signed-cert" option is required. Added automatically.'

const platform = flags.platform
if (platform === 'minikube' || platform === 'crc' || platform === 'minishift') {
// There is no way to use real certificate on listed above platforms
cli.warn(warningMessage)
flags['self-signed-cert'] = true
task.title = `${task.title}... self-signed`
return
}

if (flags.domain && (flags.domain.endsWith('nip.io') || flags.domain.endsWith('xip.io'))) {
// It is not possible to use real certificate with *.nip.io and similar services
cli.warn(warningMessage)
flags['self-signed-cert'] = true
task.title = `${task.title}... self-signed`
return
}

// TODO check the secret certificate if it is commonly trusted.
cli.info('TLS mode is turned on, however we failed to determine whether self-signed certificate is used. \n\
Please rerun chectl with "--self-signed-cert" option if it is the case, otherwise Eclipse Che will fail to start.')
}
}
}

export function retrieveCheCaCertificateTask(flags: any): Listr.ListrTask {
return {
title: 'Retrieving Che self-signed CA certificate',
// It makes sense to retrieve CA certificate only if self-signed certificate is used.
enabled: () => flags.tls && flags['self-signed-cert'] && flags.installer !== 'helm',
enabled: () => flags.tls && flags.installer !== 'helm',
task: async (ctx: any, task: any) => {
const che = new CheHelper(flags)
const cheCaCert = await che.retrieveCheCaCert(flags.chenamespace)
const targetFile = await che.saveCheCaCert(cheCaCert)
if (cheCaCert) {
const targetFile = await che.saveCheCaCert(cheCaCert)

task.title = `${task.title }... is exported to ${targetFile}`
ctx.highlightedMessages.push(getMessageImportCaCertIntoBrowser(targetFile))
} else {
task.title = `${task.title }... commonly trusted certificate is used.`
}

task.title = `${task.title }... is exported to ${targetFile}`
ctx.highlightedMessages.push(getMessageImportCaCertIntoBrowser(targetFile))
}
}
}
Expand Down
30 changes: 16 additions & 14 deletions src/tasks/installers/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as path from 'path'
import { CheHelper } from '../../api/che'
import { KubeHelper } from '../../api/kube'
import { VersionHelper } from '../../api/version'
import { CHE_TLS_SECRET_NAME } from '../../constants'
import { CHE_ROOT_CA_SECRET_NAME, CHE_TLS_SECRET_NAME } from '../../constants'
import { CertManagerTasks } from '../../tasks/component-installers/cert-manager'
import { generatePassword, isStableVersion } from '../../util'

Expand Down Expand Up @@ -78,25 +78,28 @@ export class HelmTasks {
{
title: 'Check Eclipse Che TLS certificate',
task: async (ctx: any, task: any) => {
const cheTlsSecret = await this.kubeHelper.getSecret(CHE_TLS_SECRET_NAME, flags.chenamespace)

const fixErrorMessage = 'Helm installer generates secrets automatically. To fix the problem delete existed secrets in dedicated for Eclispe Che namespace and rerun the command.'
if (cheTlsSecret && cheTlsSecret.data) {
if (!cheTlsSecret.data['tls.crt'] || !cheTlsSecret.data['tls.key']) {
throw new Error('"che-tls" secret is found but it is invalid. The valid self-signed certificate should contain "tls.crt" and "tls.key" entries. ' + fixErrorMessage)

const cheTlsSecret = await this.kubeHelper.getSecret(CHE_TLS_SECRET_NAME, flags.chenamespace)
if (cheTlsSecret) {
if (!cheTlsSecret.data || !cheTlsSecret.data['tls.crt'] || !cheTlsSecret.data['tls.key']) {
throw new Error('"che-tls" secret is found but it is invalid. The valid secret should contain "tls.crt" and "tls.key" entries. ' + fixErrorMessage)
}
if (flags['self-signed-cert'] && !cheTlsSecret.data['ca.crt']) {
throw new Error(`"ca.crt" should be present in ${CHE_TLS_SECRET_NAME} secret in case of using self-signed certificate with helm installer. ${fixErrorMessage}`)
const selfSignedCertSecret = await this.kubeHelper.getSecret(CHE_ROOT_CA_SECRET_NAME, flags.chenamespace)
if (selfSignedCertSecret && (!selfSignedCertSecret.data || !selfSignedCertSecret.data['ca.crt'])) {
throw new Error(`"ca.crt" should be present in ${CHE_ROOT_CA_SECRET_NAME} secret in case of using self-signed certificate with helm installer. ${fixErrorMessage}`)
}

ctx.cheCertificateExists = true

task.title = `${task.title}...self-signed certificate secret found`
if (selfSignedCertSecret) {
task.title = `${task.title}...self-signed TLS certificate secret found`
} else {
task.title = `${task.title}...TLS certificate secret found`
}
} else {
// TLS certificate for Eclipse Che hasn't been added into the cluster manually, so we need to take care about it automatically
ctx.cheCertificateExists = false
// Set self-signed certificate flag to true as we are going to generate one
flags['self-signed-cert'] = true

task.title = `${task.title}...going to generate self-signed one`

Expand Down Expand Up @@ -312,9 +315,8 @@ error: E_COMMAND_FAILED`)
tlsFlag = `-f ${destDir}values/tls.yaml`
}

if (flags['self-signed-cert']) {
setOptions.push('--set global.tls.useSelfSignedCerts=true')
}
const selfSignedCertSecretExists = !! await this.kubeHelper.getSecret(CHE_TLS_SECRET_NAME, flags.chenamespace)
setOptions.push(`--set global.tls.useSelfSignedCerts=${selfSignedCertSecretExists}`)

if (flags['plugin-registry-url']) {
setOptions.push(`--set che.workspace.pluginRegistryUrl=${flags['plugin-registry-url']} --set chePluginRegistry.deploy=false`)
Expand Down
3 changes: 1 addition & 2 deletions src/tasks/installers/olm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { CatalogSource, Subscription } from '../../api/typings/olm'
import { CUSTOM_CATALOG_SOURCE_NAME, CVS_PREFIX, DEFAULT_CHE_IMAGE, DEFAULT_CHE_OLM_PACKAGE_NAME, DEFAULT_OLM_KUBERNETES_NAMESPACE, DEFAULT_OPENSHIFT_MARKET_PLACE_NAMESPACE, KUBERNETES_OLM_CATALOG, OLM_STABLE_CHANNEL_NAME, OPENSHIFT_OLM_CATALOG, OPERATOR_GROUP_NAME, SUBSCRIPTION_NAME } from '../../constants'
import { isKubernetesPlatformFamily } from '../../util'

import { checkTlsCertificate, copyOperatorResources, createEclipseCheCluster, createNamespaceTask } from './common-tasks'
import { copyOperatorResources, createEclipseCheCluster, createNamespaceTask } from './common-tasks'

export class OLMTasks {
/**
Expand All @@ -32,7 +32,6 @@ export class OLMTasks {
this.isOlmPreInstalledTask(command, kube),
copyOperatorResources(flags, command.config.cacheDir),
createNamespaceTask(flags),
checkTlsCertificate(flags),
{
title: 'Create operator group',
task: async (_ctx: any, task: any) => {
Expand Down
3 changes: 1 addition & 2 deletions src/tasks/installers/operator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { KubeHelper } from '../../api/kube'
import { CHE_CLUSTER_CRD } from '../../constants'
import { isStableVersion } from '../../util'

import { checkTlsCertificate, copyOperatorResources, createEclipseCheCluster, createNamespaceTask } from './common-tasks'
import { copyOperatorResources, createEclipseCheCluster, createNamespaceTask } from './common-tasks'

export class OperatorTasks {
operatorServiceAccount = 'che-operator'
Expand All @@ -40,7 +40,6 @@ export class OperatorTasks {
return new Listr([
copyOperatorResources(flags, command.config.cacheDir),
createNamespaceTask(flags),
checkTlsCertificate(flags),
{
title: `Create ServiceAccount ${this.operatorServiceAccount} in namespace ${flags.chenamespace}`,
task: async (ctx: any, task: any) => {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/minikube.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('Eclipse Che deploy test suite', () => {
test
.stdout({ print: true })
.stderr({ print: true })
.command(['server:start', '--platform=minikube', '--che-operator-cr-patch-yaml=test/e2e/util/cr-test.yaml', '--tls', '--self-signed-cert', '--installer=operator', '--skip-cluster-availability-check'])
.command(['server:start', '--platform=minikube', '--che-operator-cr-patch-yaml=test/e2e/util/cr-test.yaml', '--tls', '--installer=operator', '--skip-cluster-availability-check'])
.exit(0)
.it('uses minikube as platform, operator as installer and auth is enabled')
test
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/minishift.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('Eclipse Che deploy test suite', () => {
test
.stdout({ print: true })
.stderr({ print: true })
.command(['server:start', '--platform=minishift', '--che-operator-cr-patch-yaml=test/e2e/util/cr-test.yaml', '--tls', '--self-signed-cert', '--installer=operator'])
.command(['server:start', '--platform=minishift', '--che-operator-cr-patch-yaml=test/e2e/util/cr-test.yaml', '--tls', '--installer=operator'])
.exit(0)
.it('uses minishift as platform, operator as installer and auth is enabled')
test
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1523,13 +1523,13 @@ ecc-jsbn@~0.1.1:
version "0.0.0"
resolved "git://github.com/minishift/minishift#2410ad2f582558e0d8b001582d0f4e43311c81be"

"eclipse-che-operator@git://github.com/eclipse/che-operator#7.14.2":
"eclipse-che-operator@git://github.com/eclipse/che-operator#7.14.x":
version "0.0.0"
resolved "git://github.com/eclipse/che-operator#7bf371efde88fe2f0e8e3aead4800d70770099ae"
resolved "git://github.com/eclipse/che-operator#8458673a49e6f594a43ba5ab61d4d18eeed6e718"

"eclipse-che@git://github.com/eclipse/che#7.14.2":
"eclipse-che@git://github.com/eclipse/che#7.14.x":
version "0.0.0"
resolved "git://github.com/eclipse/che#0f85019fee54966d6c78efb366884eee682469c8"
resolved "git://github.com/eclipse/che#28c1f3a9c5934e0429a731b82dbca00b2f2e39c4"

editorconfig@^0.15.0:
version "0.15.3"
Expand Down