Skip to content

Commit

Permalink
feat: Add cacert:export command to get Che self-signed CA certificate (
Browse files Browse the repository at this point in the history
…#669)

Add cacert:export command to get Che self-signed CA certificate
  • Loading branch information
mmorhun committed Apr 27, 2020
1 parent 16451f2 commit 2e85527
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ USAGE
# Commands
<!-- commands -->
* [`chectl autocomplete [SHELL]`](#chectl-autocomplete-shell)
* [`chectl cacert:export`](#chectl-cacertexport)
* [`chectl dashboard:open`](#chectl-dashboardopen)
* [`chectl devfile:generate`](#chectl-devfilegenerate)
* [`chectl help [COMMAND]`](#chectl-help-command)
Expand Down Expand Up @@ -123,6 +124,37 @@ EXAMPLES

_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v0.1.5/src/commands/autocomplete/index.ts)_

## `chectl cacert:export`

Retrieves Eclipse Che self-signed certificate

```
USAGE
$ chectl cacert:export
OPTIONS
-d, --destination=destination
Destination where to store Che self-signed CA certificate.
If the destination is a file (might not exist), then the certificate will be saved there in PEM
format.
If the destination is a directory, then cheCA.crt file will be created there with Che
certificate in PEM format.
If this option is ommited, then Che certificate will be stored in user's home directory as
cheCA.crt
-h, --help
show CLI help
-n, --chenamespace=chenamespace
[default: che] Kubernetes namespace where Eclipse Che server is supposed to be deployed
-p, --platform=minikube|minishift|k8s|openshift|microk8s|docker-desktop|crc
Type of Kubernetes platform. Valid values are "minikube", "minishift", "k8s (for kubernetes)", "openshift", "crc
(for CodeReady Containers)", "microk8s".
```

_See code: [src/commands/cacert/export.ts](https://github.com/che-incubator/chectl/blob/v0.0.2/src/commands/cacert/export.ts)_

## `chectl dashboard:open`

Open Eclipse Che dashboard
Expand Down Expand Up @@ -322,6 +354,7 @@ OPTIONS
--catalog-source-yaml=catalog-source-yaml
Path to a yaml file that describes custom catalog source for installation Eclipse Che operator.
Catalog source will be applied to the namespace with Che operator.
Also you need define 'olm-channel' name and 'package-manifest-name'.
This parameter is used only when the installer is the 'olm'.
--che-operator-cr-patch-yaml=che-operator-cr-patch-yaml
Expand Down
17 changes: 17 additions & 0 deletions src/api/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as yaml from 'js-yaml'
import * as path from 'path'

import { OpenShiftHelper } from '../api/openshift'
import { CHE_ROOT_CA_SECRET_NAME } from '../constants'

import { Devfile } from './devfile'
import { KubeHelper } from './kube'
Expand Down Expand Up @@ -107,6 +108,22 @@ export class CheHelper {
}
}

/**
* Gets self-signed Che CA certificate from 'self-signed-certificate' secret. The secret should exist.
*/
async retrieveEclipseCheCaCert(cheNamespace: string): Promise<string> {
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?')
}

if (cheCaSecret.data && cheCaSecret.data['ca.crt']) {
return Buffer.from(cheCaSecret.data['ca.crt'], 'base64').toString('ascii')
}

throw new Error(`Secret "${CHE_ROOT_CA_SECRET_NAME}" has invalid format: "ca.crt" key not found in data.`)
}

async cheK8sURL(namespace = ''): Promise<string> {
const ingress_names = ['che', 'che-ingress']
for (const ingress_name of ingress_names) {
Expand Down
88 changes: 88 additions & 0 deletions src/commands/cacert/export.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*********************************************************************
* Copyright (c) 2020 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/

import { Command, flags } from '@oclif/command'
import { string } from '@oclif/parser/lib/flags'
import * as fs from 'fs'
import * as Listr from 'listr'
import * as os from 'os'
import * as path from 'path'

import { CheHelper } from '../../api/che'
import { cheNamespace } from '../../common-flags'
import { CheTasks } from '../../tasks/che'
import { ApiTasks } from '../../tasks/platforms/api'
import { PlatformTasks } from '../../tasks/platforms/platform'

const DEFAULT_CA_CERT_FILE_NAME = 'cheCA.crt'

export default class Export extends Command {
static description = 'Retrieves Eclipse Che self-signed certificate'

static flags = {
help: flags.help({ char: 'h' }),
chenamespace: cheNamespace,
platform: string({
char: 'p',
description: 'Type of Kubernetes platform. Valid values are \"minikube\", \"minishift\", \"k8s (for kubernetes)\", \"openshift\", \"crc (for CodeReady Containers)\", \"microk8s\".',
options: ['minikube', 'minishift', 'k8s', 'openshift', 'microk8s', 'docker-desktop', 'crc'],
}),
destination: string({
char: 'd',
description: `Destination where to store Che CA certificate.
If the destination is a file (might not exist), then the certificate will be saved there in PEM format.
If the destination is a directory, then ${DEFAULT_CA_CERT_FILE_NAME} file will be created there with Che certificate in PEM format.
If this option is ommited, then Che certificate will be stored in user's home directory as ${DEFAULT_CA_CERT_FILE_NAME}`,
env: 'CHE_CA_CERT_LOCATION',
default: ''
}),
}

async run() {
const { flags } = this.parse(Export)
const ctx: any = {}
const cheHelper = new CheHelper(flags)
const platformTasks = new PlatformTasks()
const cheTasks = new CheTasks(flags)
const apiTasks = new ApiTasks()
const tasks = new Listr([], { renderer: 'silent' })

const targetFile = this.getTargetFile(flags.destination)

tasks.add(platformTasks.preflightCheckTasks(flags, this))
tasks.add(apiTasks.testApiTasks(flags, this))
tasks.add(cheTasks.verifyCheNamespaceExistsTask(flags, this))

try {
await tasks.run(ctx)
const cheCaCert = await cheHelper.retrieveEclipseCheCaCert(flags.chenamespace)
fs.writeFileSync(targetFile, cheCaCert)
this.log(`Eclipse Che self-signed CA certificate is exported to ${targetFile}`)
} catch (error) {
this.error(error)
}
}

/**
* Handles certificate target location and returns string which points to the target file.
*/
private getTargetFile(destinaton: string): string {
if (!destinaton) {
return path.join(os.homedir(), DEFAULT_CA_CERT_FILE_NAME)
}

if (fs.existsSync(destinaton)) {
return fs.lstatSync(destinaton).isDirectory() ? path.join(destinaton, DEFAULT_CA_CERT_FILE_NAME) : destinaton
}

this.error(`Given path "${destinaton}" doesn\'t exist.`)
}

}
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const CA_CERT_GENERATION_JOB_IMAGE = 'quay.io/eclipse/che-cert-manager-ca

export const CERT_MANAGER_NAMESPACE_NAME = 'cert-manager'
export const CHE_TLS_SECRET_NAME = 'che-tls'
export const CHE_ROOT_CA_SECRET_NAME = 'self-signed-certificate'

export const operatorCheCluster = 'eclipse-che'
export const CHE_CLUSTER_CR_NAME = 'eclipse-che'
Expand Down

0 comments on commit 2e85527

Please sign in to comment.