Skip to content

Commit

Permalink
feat: Make cacert export save only CA certificates (#859)
Browse files Browse the repository at this point in the history
* Make cacert:export save only the last certificate in the chain

Signed-off-by: Mykola Morhun <mmorhun@redhat.com>
  • Loading branch information
mmorhun committed Sep 21, 2020
1 parent d09bb12 commit 68646b8
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 12 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"listr-verbose-renderer": "^0.6.0",
"lodash": "^4.17.20",
"mkdirp": "^1.0.4",
"node-forge": "^0.10.0",
"node-notifier": "^8.0.0",
"stream-buffers": "^3.0.2",
"tslib": "^1"
Expand All @@ -51,6 +52,7 @@
"@types/js-yaml": "^3.12.5",
"@types/listr": "^0.14.2",
"@types/node": "^12",
"@types/node-forge": "^0.9.5",
"chai": "^4.2.0",
"cpx": "^1.5.0",
"globby": "^11",
Expand Down
30 changes: 30 additions & 0 deletions src/api/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import * as commandExists from 'command-exists'
import * as fs from 'fs-extra'
import * as https from 'https'
import * as yaml from 'js-yaml'
import * as nodeforge from 'node-forge'
import * as os from 'os'
import * as path from 'path'

Expand Down Expand Up @@ -120,6 +121,35 @@ export class CheHelper {
* If secret doesn't exist, undefined is returned.
*/
async retrieveCheCaCert(cheNamespace: string): Promise<string | undefined> {
const cheCaSecretContent = await this.getCheSelfSignedSecretContent(cheNamespace)
if (!cheCaSecretContent) {
return
}

const pemBeginHeader = '-----BEGIN CERTIFICATE-----'
const pemEndHeader = '-----END CERTIFICATE-----'
const certRegExp = new RegExp(`(^${pemBeginHeader}$(?:(?!${pemBeginHeader}).)*^${pemEndHeader}$)`, 'mgs')
const certsPem = cheCaSecretContent.match(certRegExp)

const caCertsPem: string[] = []
if (certsPem) {
for (const certPem of certsPem) {
const cert = nodeforge.pki.certificateFromPem(certPem)
const basicConstraintsExt = cert.getExtension('basicConstraints')
if (basicConstraintsExt && (basicConstraintsExt as any).cA) {
caCertsPem.push(certPem)
}
}
}

return caCertsPem.join('\n')
}

/**
* Retrieves content of Che self-signed-certificate secret or undefined if the secret doesn't exist.
* Note, it contains certificate chain in pem format.
*/
private async getCheSelfSignedSecretContent(cheNamespace: string): Promise<string | undefined> {
const cheCaSecret = await this.kube.getSecret(CHE_ROOT_CA_SECRET_NAME, cheNamespace)
if (!cheCaSecret) {
return
Expand Down
20 changes: 9 additions & 11 deletions src/commands/cacert/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
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 { KubeHelper } from '../../api/kube'
import { cheNamespace, skipKubeHealthzCheck } from '../../common-flags'
import { DEFAULT_CA_CERT_FILE_NAME } from '../../constants'
import { CheTasks } from '../../tasks/che'
import { ApiTasks } from '../../tasks/platforms/api'

export default class Export extends Command {
static description = 'Retrieves Eclipse Che self-signed certificate'
Expand All @@ -41,23 +39,23 @@ export default class Export extends Command {

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

tasks.add(apiTasks.testApiTasks(flags, this))
tasks.add(cheTasks.verifyCheNamespaceExistsTask(flags, this))
if (!await kube.hasReadPermissionsForNamespace(flags.chenamespace)) {
throw new Error(`E_PERM_DENIED - Permission denied: no read access to '${flags.chenamespace}' namespace`)
}
if (!await cheHelper.cheNamespaceExist(flags.chenamespace)) {
throw new Error(`E_BAD_NS - Namespace ${flags.chenamespace} does not exist. Please specify it with --chenamespace flag`)
}

try {
await tasks.run(ctx)
const cheCaCert = await cheHelper.retrieveCheCaCert(flags.chenamespace)
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.')
this.log('Self signed certificate secret not found. Is commonly trusted certificate used?')
}
} catch (error) {
this.error(error)
Expand Down
2 changes: 1 addition & 1 deletion src/tasks/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ export class CheTasks {
title: `Verify if namespace '${flags.chenamespace}' exists`,
task: async () => {
if (!await this.che.cheNamespaceExist(flags.chenamespace)) {
command.error(`E_BAD_NS - Namespace does not exist.\nThe Kubernetes Namespace "${flags.chenamespace}" doesn't exist. The configuration cannot be injected.\nFix with: verify the namespace where workspace is running (kubectl get --all-namespaces deployment | grep workspace)`, { code: 'EBADNS' })
command.error(`E_BAD_NS - Namespace does not exist.\nThe Kubernetes Namespace "${flags.chenamespace}" doesn't exist.`, { code: 'EBADNS' })
}
}
}]
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,13 @@
dependencies:
"@types/node" "*"

"@types/node-forge@^0.9.5":
version "0.9.5"
resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-0.9.5.tgz#648231d79da197216290429020698d4e767365a0"
integrity sha512-rrN3xfA/oZIzwOnO3d2wRQz7UdeVkmMMPjWUCfpPTPuKFVb3D6G10LuiVHYYmvrivBBLMx4m0P/FICoDbNZUMA==
dependencies:
"@types/node" "*"

"@types/node-notifier@^8.0.0":
version "8.0.0"
resolved "https://registry.yarnpkg.com/@types/node-notifier/-/node-notifier-8.0.0.tgz#51100d67155ed1500a8aaa633987109f59a0637d"
Expand Down Expand Up @@ -4256,6 +4263,11 @@ nock@^11.7.0:
mkdirp "^0.5.0"
propagate "^2.0.0"

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.8.5:
version "0.8.5"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.5.tgz#57906f07614dc72762c84cef442f427c0e1b86ee"
Expand Down

0 comments on commit 68646b8

Please sign in to comment.