Skip to content

Commit

Permalink
feat: [Operator] Retrieve autogenerated Keycloak admin user credentia…
Browse files Browse the repository at this point in the history
…ls (#690)

* Retrieve autogenerated Keycloak admin user credentials after Che deployment finish

Signed-off-by: Mykola Morhun <mmorhun@redhat.com>
  • Loading branch information
mmorhun committed May 13, 2020
1 parent 3aa65b7 commit 8534a03
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 7 deletions.
33 changes: 31 additions & 2 deletions src/api/che.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import * as os from 'os'
import * as path from 'path'

import { OpenShiftHelper } from '../api/openshift'
import { CHE_ROOT_CA_SECRET_NAME, DEFAULT_CA_CERT_FILE_NAME } from '../constants'
import { CHE_CLUSTER_CR_NAME, CHE_ROOT_CA_SECRET_NAME, DEFAULT_CA_CERT_FILE_NAME } from '../constants'
import { base64Decode } from '../util'

import { Devfile } from './devfile'
import { KubeHelper } from './kube'
Expand Down Expand Up @@ -119,7 +120,7 @@ export class CheHelper {
}

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

throw new Error(`Secret "${CHE_ROOT_CA_SECRET_NAME}" has invalid format: "ca.crt" key not found in data.`)
Expand All @@ -139,6 +140,34 @@ export class CheHelper {
return destinaton
}

/**
* Retreives Keycloak admin user credentials.
* Works only with installers which use Che CR (operator, olm).
* Returns credentials as an array of two values: [login, password]
* In case of an error an array with undefined values will be returned.
*/
async retrieveKeycloakAdminCredentials(cheNamespace: string): Promise<string[]> {
let adminUsername
let adminPassword

const cheCluster = await this.kube.getCheCluster(CHE_CLUSTER_CR_NAME, cheNamespace)
const keycloakCredentialsSecretName = cheCluster.spec.auth.identityProviderSecret
if (keycloakCredentialsSecretName) {
// Keycloak credentials are stored in secret
const keycloakCredentialsSecret = await this.kube.getSecret(keycloakCredentialsSecretName, cheNamespace)
if (keycloakCredentialsSecret && keycloakCredentialsSecret.data) {
adminUsername = base64Decode(keycloakCredentialsSecret.data.user)
adminPassword = base64Decode(keycloakCredentialsSecret.data.password)
}
} else {
// Keycloak credentials are stored in Che custom resource
adminUsername = cheCluster.spec.auth.identityProviderAdminUserName
adminPassword = cheCluster.spec.auth.identityProviderPassword
}

return [adminUsername, adminPassword]
}

async cheK8sURL(namespace = ''): Promise<string> {
const ingress_names = ['che', 'che-ingress']
for (const ingress_name of ingress_names) {
Expand Down
3 changes: 2 additions & 1 deletion src/commands/server/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import * as path from 'path'
import { cheDeployment, cheNamespace, listrRenderer, skipKubeHealthzCheck as skipK8sHealthCheck } from '../../common-flags'
import { DEFAULT_CHE_IMAGE, DEFAULT_CHE_OPERATOR_IMAGE, DOCS_LINK_INSTALL_TLS_WITH_SELF_SIGNED_CERT } from '../../constants'
import { CheTasks } from '../../tasks/che'
import { retrieveCheCaCertificateTask } from '../../tasks/installers/common-tasks'
import { getRetrieveKeycloakCredentialsTask, retrieveCheCaCertificateTask } from '../../tasks/installers/common-tasks'
import { InstallerTasks } from '../../tasks/installers/installer'
import { ApiTasks } from '../../tasks/platforms/api'
import { PlatformTasks } from '../../tasks/platforms/platform'
Expand Down Expand Up @@ -351,6 +351,7 @@ export default class Start extends Command {
title: '✅ Post installation checklist',
task: () => new Listr(cheTasks.waitDeployedChe(flags, this))
},
getRetrieveKeycloakCredentialsTask(flags),
retrieveCheCaCertificateTask(flags),
{
title: 'Show important messages',
Expand Down
3 changes: 2 additions & 1 deletion src/tasks/component-installers/cert-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,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 { base64Decode } from '../../util'
import { getMessageImportCaCertIntoBrowser } from '../installers/common-tasks'

export const CERT_MANAGER_CA_SECRET_NAME = 'ca'
Expand Down Expand Up @@ -167,7 +168,7 @@ export class CertManagerTasks {
task: async (ctx: any, task: any) => {
const cheSecret = await this.kubeHelper.getSecret(CHE_TLS_SECRET_NAME, flags.chenamespace)
if (cheSecret && cheSecret.data) {
const cheCaCrt = Buffer.from(cheSecret.data['ca.crt'], 'base64').toString('ascii')
const cheCaCrt = base64Decode(cheSecret.data['ca.crt'])
const cheCaCertPath = await this.cheHelper.saveCheCaCert(cheCaCrt)

ctx.highlightedMessages.push(getMessageImportCaCertIntoBrowser(cheCaCertPath))
Expand Down
21 changes: 20 additions & 1 deletion src/tasks/installers/common-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export function createEclipeCheCluster(flags: any, kube: KubeHelper): ListrTask

const yamlFilePath = flags['che-operator-cr-yaml'] === '' ? ctx.resourcesPath + 'crds/org_v1_che_cr.yaml' : flags['che-operator-cr-yaml']
const cr = await kube.createCheClusterFromFile(yamlFilePath, flags, flags['che-operator-cr-yaml'] === '')
ctx.cr = cr
ctx.isKeycloakReady = ctx.isKeycloakReady || cr.spec.auth.externalIdentityProvider
ctx.isPostgresReady = ctx.isPostgresReady || cr.spec.database.externalDb
ctx.isDevfileRegistryReady = ctx.isDevfileRegistryReady || cr.spec.server.externalDevfileRegistry
Expand Down Expand Up @@ -151,6 +152,24 @@ export function getMessageImportCaCertIntoBrowser(caCertFileLocation: string): s
const yellow = '\x1b[33m'
const noColor = '\x1b[0m'
const message = `❗${yellow}[MANUAL ACTION REQUIRED]${noColor} Please add Che self-signed CA certificate into your browser: ${caCertFileLocation}.\n` +
`Documentaton how to add a CA certificate into a browser: ${DOCS_LINK_IMPORT_CA_CERT_INTO_BROWSER}`
`Documentation how to add a CA certificate into a browser: ${DOCS_LINK_IMPORT_CA_CERT_INTO_BROWSER}`
return message
}

export function getRetrieveKeycloakCredentialsTask(flags: any): ListrTask {
return {
title: 'Retrieving Keycloak admin credentials',
enabled: (ctx: any) => !ctx.cr.spec.auth.externalIdentityProvider && flags.multiuser && (flags.installer !== 'operator' || flags.installer !== 'olm'),
task: async (ctx: any, task: any) => {
const che = new CheHelper(flags)
const [login, password] = await che.retrieveKeycloakAdminCredentials(flags.chenamespace)
if (login && password) {
ctx.highlightedMessages.push(`Autogenerated Keycloak credentials are: "${login}:${password}".`)

task.title = `${task.title }... ${login}:${password}`
} else {
task.title = `${task.title }... Failed.`
}
}
}
}
4 changes: 4 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,7 @@ export function generatePassword(passwodLength: number, charactersSet = '') {
}
return generatedPassword
}

export function base64Decode(arg: string): string {
return Buffer.from(arg, 'base64').toString('ascii')
}
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1521,11 +1521,11 @@ ecc-jsbn@~0.1.1:

"eclipse-che-operator@git://github.com/eclipse/che-operator#master":
version "0.0.0"
resolved "git://github.com/eclipse/che-operator#b0a62e0f4de376a7aa4e260ce1b1774bc32d2784"
resolved "git://github.com/eclipse/che-operator#0c671d8a117a333ee36756e5d3a4a75171d64b14"

"eclipse-che@git://github.com/eclipse/che#master":
version "0.0.0"
resolved "git://github.com/eclipse/che#6333d8951a949628e0c80bf61406efed6064ceca"
resolved "git://github.com/eclipse/che#0fd09abd02140545c49b28bce186512afeb04336"

editorconfig@^0.15.0:
version "0.15.3"
Expand Down

0 comments on commit 8534a03

Please sign in to comment.