Skip to content

Commit

Permalink
KMS flow for storage class creation
Browse files Browse the repository at this point in the history
Signed-off-by: Kanika Murarka <kmurarka@redhat.com>
  • Loading branch information
Kanika Murarka committed Dec 1, 2020
1 parent 7ef1abc commit ba390fc
Show file tree
Hide file tree
Showing 11 changed files with 551 additions and 88 deletions.
@@ -1,4 +1,8 @@
.ocs-install-kms {
&__heading {
margin-left: var(--pf-global--spacer--md);
}

&__form-url {
display: inline-flex;
width: 100%;
Expand All @@ -11,4 +15,9 @@
&__form-port {
width: 30%;
}

&__save-button {
margin-left: var(--pf-global--spacer--md);
margin-bottom: var(--pf-global--spacer--md);
}
}
@@ -1,6 +1,7 @@
import * as React from 'react';
import * as _ from 'lodash';

import * as classNames from 'classnames';
import {
FormGroup,
TextInput,
Expand All @@ -22,10 +23,11 @@ import { KMSProviders } from '../../constants/ocs-install';
import { KMSConfig } from '../ocs-install/types';
import { State, Action } from '../ocs-install/attached-devices/create-sc/state';
import { setEncryptionDispatch, parseURL } from './utils';
import { StorageClassState, StorageClassClusterAction } from '../../utils/storage-pool';

import './kms-config.scss';

export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mode }) => {
export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mode, className }) => {
const { kms } = state;
const [kmsProvider, setKMSProvider] = React.useState<string>(KMSProviders[0].name);

Expand Down Expand Up @@ -80,10 +82,11 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod

return (
<div className="co-m-pane__form">
{!mode && <h3 className="ocs-install-kms__heading">Connect to a Key Management Service</h3>}
<FormGroup
fieldId="kms-provider"
label="Key Management Service Provider"
className="ocs-install-encryption__form-body"
className={`${className}__form-body`}
>
<FormSelect
value={kmsProvider}
Expand All @@ -101,7 +104,7 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
<FormGroup
fieldId="kms-service-name"
label="Service Name"
className="ocs-install-encryption__form-body"
className={`${className}__form-body`}
helperTextInvalid="This is a required field"
validated={kms.name.valid ? ValidatedOptions.default : ValidatedOptions.error}
isRequired
Expand All @@ -120,7 +123,7 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
<FormGroup
fieldId="kms-service-address"
label="Address"
className="ocs-install-kms__form-address ocs-install-encryption__form-body"
className={classNames('ocs-install-kms__form-address', `${className}__form-body`)}
helperTextInvalid={validateAddressMessage()}
validated={kms.address.valid ? ValidatedOptions.default : ValidatedOptions.error}
isRequired
Expand All @@ -139,7 +142,10 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
<FormGroup
fieldId="kms-service-address-port"
label="Port"
className="ocs-install-kms__form-port ocs-install-encryption__form-body--small-padding"
className={classNames(
'ocs-install-kms__form-port',
`${className}__form-body--small-padding`,
)}
helperTextInvalid={validatePortMessage()}
validated={kms.port.valid ? ValidatedOptions.default : ValidatedOptions.error}
isRequired
Expand All @@ -155,29 +161,27 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
/>
</FormGroup>
</div>
<FormGroup
fieldId="kms-service-token"
label="Token"
className="ocs-install-encryption__form-body"
helperTextInvalid="This is a required field"
validated={kms.token.valid ? ValidatedOptions.default : ValidatedOptions.error}
isRequired
>
<TextInput
value={kms.token.value}
onChange={setToken}
type="password"
id="kms-token"
name="kms-token"
isRequired
{(mode || kms.token.value) && (
<FormGroup
fieldId="kms-service-token"
label="Token"
className={`${className}__form-body`}
helperTextInvalid="This is a required field"
validated={kms.token.valid ? ValidatedOptions.default : ValidatedOptions.error}
/>
</FormGroup>
<Button
variant="link"
className="ocs-install-encryption__form-body"
onClick={openAdvancedModal}
>
isRequired
>
<TextInput
value={kms.token.value}
onChange={setToken}
type="password"
id="kms-token"
name="kms-token"
isRequired
validated={kms.token.valid ? ValidatedOptions.default : ValidatedOptions.error}
/>
</FormGroup>
)}
<Button variant="link" className={`${className}__form-body`} onClick={openAdvancedModal}>
Advanced Settings{' '}
{(kms.backend ||
kms.caCert ||
Expand All @@ -193,7 +197,8 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
};

type KMSConfigureProps = {
state: InternalClusterState | State;
dispatch: React.Dispatch<Action | InternalClusterAction>;
state: InternalClusterState | State | StorageClassState;
dispatch: React.Dispatch<Action | InternalClusterAction | StorageClassClusterAction>;
mode?: string;
className: string;
};
@@ -1,12 +1,13 @@
import * as React from 'react';
import * as _ from 'lodash';
import { K8sResourceKind, ConfigMapKind, SecretKind } from '@console/internal/module/k8s/types';
import { k8sCreate } from '@console/internal/module/k8s/resource';
import { k8sCreate, k8sPatch } from '@console/internal/module/k8s/resource';
import { ConfigMapModel, SecretModel } from '@console/internal/models';
import { CEPH_STORAGE_NAMESPACE, MODES, KMSConfigMapName, KMSSecretName } from '../../constants';
import { Action } from '../ocs-install/attached-devices/create-sc/state';
import { InternalClusterAction } from '../ocs-install/internal-mode/reducer';
import { KMSConfig, KMSConfigMap } from '../ocs-install/types';
import { StorageClassClusterAction } from '../../utils/storage-pool';

export const parseURL = (url: string) => {
try {
Expand All @@ -16,7 +17,43 @@ export const parseURL = (url: string) => {
}
};

export const kmsResources = (kms: KMSConfig) => {
export const generateCASecret = (caCertificate: string) => ({
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
name: 'ocs-kms-ca-secret',
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
'ca.cert': caCertificate,
},
});

export const generateClientSecret = (clientCertificate: string) => ({
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
name: 'ocs-kms-client-cert',
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
'tls.cert': clientCertificate,
},
});

export const generateClientKeySecret = (clientKey: string) => ({
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
name: 'ocs-kms-client-key',
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
'tls.key': clientKey,
},
});

export const kmsResources = (kms: KMSConfig, update = false) => {
const tokenSecret: SecretKind = {
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
Expand All @@ -34,6 +71,7 @@ export const kmsResources = (kms: KMSConfig) => {

const configData: KMSConfigMap = {
KMS_PROVIDER: 'vault',
KMS_SERVICE_NAME: kms.name.value,
VAULT_ADDR: `${`${parsedAddress.protocol}//${parsedAddress.hostname}`}:${kms.port.value}`,
VAULT_BACKEND_PATH: kms.backend,
VAULT_CACERT: kms.caCert?.metadata.name,
Expand Down Expand Up @@ -66,15 +104,35 @@ export const kmsResources = (kms: KMSConfig) => {
resources.push(k8sCreate(SecretModel, kms.clientKey, CEPH_STORAGE_NAMESPACE));
}

resources.push(k8sCreate(SecretModel, tokenSecret, CEPH_STORAGE_NAMESPACE));
resources.push(k8sCreate(ConfigMapModel, configMapObj, CEPH_STORAGE_NAMESPACE));
if (update) {
const tokenPatch = [
{
op: 'replace',
path: '/data/data',
value: kms.token.value,
},
];
const cmPatch = [
{
op: 'replace',
path: '/data',
value: configData,
},
];
resources.push(k8sPatch(SecretModel, tokenSecret, tokenPatch));
resources.push(k8sPatch(ConfigMapModel, configMapObj, cmPatch));
} else {
resources.push(k8sCreate(SecretModel, tokenSecret, CEPH_STORAGE_NAMESPACE));
resources.push(k8sCreate(ConfigMapModel, configMapObj, CEPH_STORAGE_NAMESPACE));
}

return resources;
};

export const setEncryptionDispatch = (
keyType: any,
mode: string,
dispatch: React.Dispatch<Action | InternalClusterAction>,
dispatch: React.Dispatch<Action | InternalClusterAction | StorageClassClusterAction>,
valueType?: any,
) => {
const stateType = mode === MODES.ATTACHED_DEVICES ? _.camelCase(keyType) : keyType;
Expand Down
Expand Up @@ -14,8 +14,6 @@ import {
HandlePromiseProps,
withHandlePromise,
} from '@console/internal/components/utils/promise-component';
import { SecretModel } from '@console/internal/models';
import { SecretKind } from '@console/internal/module/k8s/types';

import { State, Action } from '../../ocs-install/attached-devices/create-sc/state';
import {
Expand All @@ -27,9 +25,14 @@ import {
vaultNamespaceTooltip,
kmsMaxFileUploadSize,
kmsFileSizeErrorMsg,
CEPH_STORAGE_NAMESPACE,
} from '../../../constants';
import { setEncryptionDispatch } from '../../kms-config/utils';
import {
setEncryptionDispatch,
generateCASecret,
generateClientSecret,
generateClientKeySecret,
} from '../../kms-config/utils';
import { StorageClassState, StorageClassClusterAction } from '../../../utils/storage-pool';
import './advanced-kms-modal.scss';

export const AdvancedKMSModal = withHandlePromise((props: AdvancedKMSModalProps) => {
Expand All @@ -52,41 +55,6 @@ export const AdvancedKMSModal = withHandlePromise((props: AdvancedKMSModalProps)

const submit = (event: React.FormEvent<EventTarget>) => {
event.preventDefault();
const caSecret: SecretKind = {
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
generateName: 'ocs-kms-ca-',
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
'ca.cert': caCertificate,
},
};

const clientCertSecret: SecretKind = {
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
generateName: 'ocs-kms-client-cert-',
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
'tls.cert': clientCertificate,
},
};

const clientKeySecret: SecretKind = {
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
generateName: 'ocs-kms-client-key-',
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
'tls.key': clientKey,
},
};

const kmsAdvanced = {
...kms,
Expand All @@ -96,23 +64,23 @@ export const AdvancedKMSModal = withHandlePromise((props: AdvancedKMSModalProps)
};

if (caCertificate && caCertificate !== '') {
kmsAdvanced.caCert = caSecret;
kmsAdvanced.caCert = generateCASecret(caCertificate);
kmsAdvanced.caCertFile = caCertificateFile;
} else {
kmsAdvanced.caCert = null;
kmsAdvanced.caCertFile = '';
}

if (clientCertificate && clientCertificate !== '') {
kmsAdvanced.clientCert = clientCertSecret;
kmsAdvanced.clientCert = generateClientSecret(clientCertificate);
kmsAdvanced.clientCertFile = clientCertificateFile;
} else {
kmsAdvanced.clientCert = null;
kmsAdvanced.clientCertFile = '';
}

if (clientKey && clientCertificate !== '') {
kmsAdvanced.clientKey = clientKeySecret;
kmsAdvanced.clientKey = generateClientKeySecret(clientKey);
kmsAdvanced.clientKeyFile = clientKeyFile;
} else {
kmsAdvanced.clientKey = null;
Expand Down Expand Up @@ -151,7 +119,7 @@ export const AdvancedKMSModal = withHandlePromise((props: AdvancedKMSModalProps)
};

return (
<Form
<form
onSubmit={submit}
className="modal-content modal-content--no-inner-scroll"
key="pool-form-modal"
Expand Down Expand Up @@ -270,13 +238,13 @@ export const AdvancedKMSModal = withHandlePromise((props: AdvancedKMSModalProps)
submitText="Save"
cancel={cancel}
/>
</Form>
</form>
);
});

export type AdvancedKMSModalProps = {
state: State | InternalClusterState;
dispatch: React.Dispatch<Action | InternalClusterAction>;
state: InternalClusterState | State | StorageClassState;
dispatch: React.Dispatch<Action | InternalClusterAction | StorageClassClusterAction>;
mode?: string;
} & HandlePromiseProps &
ModalComponentProps;
Expand Down
Expand Up @@ -162,7 +162,12 @@ export const EncryptionFormGroup: React.FC<EncryptionFormGroupProps> = ({
/>
</FormGroup>
{(encryption.advanced || encryption.storageClass) && (
<KMSConfigure state={state} dispatch={dispatch} mode={mode} />
<KMSConfigure
state={state}
dispatch={dispatch}
mode={mode}
className="ocs-install-encryption"
/>
)}
{validation && <ValidationMessage validation={validation} />}
</div>
Expand Down
Expand Up @@ -82,6 +82,7 @@ export enum NetworkType {
}
export type KMSConfigMap = {
KMS_PROVIDER: string;
KMS_SERVICE_NAME: string;
VAULT_ADDR: string; // address + port
VAULT_BACKEND_PATH: string;
VAULT_CACERT: string;
Expand Down

0 comments on commit ba390fc

Please sign in to comment.