Skip to content

Commit

Permalink
Add server:certificate command to get self-signed Che CA certificate
Browse files Browse the repository at this point in the history
Signed-off-by: Mykola Morhun <mmorhun@redhat.com>
  • Loading branch information
mmorhun committed Apr 24, 2020
1 parent 63b9ad0 commit 6b9e7a4
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
105 changes: 105 additions & 0 deletions src/commands/server/certificate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*********************************************************************
* 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 { boolean, 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 { 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 Certificate 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 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: '~'
}),
'make-path': boolean({
description: 'Creates path specified in "destination" parameter if it doesn\'t exist.',
default: false
}),
}

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

const targetFile = this.prepareTarget(flags.destination, flags['make-path'])
ctx.cheCaCertFile = targetFile

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

try {
await tasks.run(ctx)
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 prepareTarget(destinaton: string, makePath = false): 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
}

const baseDirectory = path.dirname(destinaton)
if (fs.existsSync(baseDirectory)) {
return destinaton
}

if (makePath) {
if (destinaton.endsWith('/')) {
fs.mkdirSync(destinaton, { recursive: true })
return path.join(destinaton, DEFAULT_CA_CERT_FILE_NAME)
} else {
fs.mkdirSync(baseDirectory, { recursive: true })
return destinaton
}
} else {
throw new Error(`Base directory "${baseDirectory}" 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
41 changes: 41 additions & 0 deletions src/tasks/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
import { Command } from '@oclif/command'
import * as fs from 'fs'
import * as Listr from 'listr'

import { CheHelper } from '../api/che'
import { KubeHelper } from '../api/kube'
import { OpenShiftHelper } from '../api/openshift'
import { CHE_ROOT_CA_SECRET_NAME } from '../constants'

import { KubeTasks } from './kube'

Expand Down Expand Up @@ -604,6 +606,45 @@ export class CheTasks {
]
}

/**
* Saves self-signed Che CA certificate into file. 'self-signed-certificate' secret should exist.
*/
retrieveEclipseCheCaCert(flags: any): ReadonlyArray<Listr.ListrTask> {
return [
{
title: 'Retrieving self-signed Eclipse Che CA certificate',
task: async (ctx: any, task: any) => {
const cheCaSecret = await this.kube.getSecret(CHE_ROOT_CA_SECRET_NAME, flags.chenamespace)
if (!cheCaSecret) {
throw new Error(`Secret "${CHE_ROOT_CA_SECRET_NAME}" not found.`)
}
if (cheCaSecret.data && cheCaSecret.data['ca.crt']) {
ctx.cheCaCert = Buffer.from(cheCaSecret.data['ca.crt'], 'base64').toString('ascii')
} else {
throw new Error(`Secret "${CHE_ROOT_CA_SECRET_NAME}" has invalid format.`)
}

task.title = `${task.title}... done`
}
},
{
title: 'Saving self-signed Eclipse Che CA certificate',
task: async (ctx: any, task: any) => {
if (!ctx.cheCaCert) {
throw new Error('Che CA certificate is not present in the context.')
}
if (!ctx.cheCaCertFile) {
throw new Error('Target file for Che CA certificate is not present in the context.')
}

fs.writeFileSync(ctx.cheCaCertFile, ctx.cheCaCert)

task.title = `Eclipse Che self-signed CA certificate is saved at ${ctx.cheCaCertFile}`
}
}
]
}

checkEclipseCheStatus(): ReadonlyArray<Listr.ListrTask> {
return [
{
Expand Down

0 comments on commit 6b9e7a4

Please sign in to comment.