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 4, 2020
1 parent 8c01735 commit 081ff72
Show file tree
Hide file tree
Showing 11 changed files with 594 additions and 108 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,8 @@
import * as React from 'react';
import * as _ from 'lodash';
import { useTranslation } from 'react-i18next';

import * as classNames from 'classnames';
import {
FormGroup,
TextInput,
Expand All @@ -22,10 +24,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 { t } = useTranslation();
const { kms } = state;
const [kmsProvider, setKMSProvider] = React.useState<string>(KMSProviders[0].name);
Expand Down Expand Up @@ -87,10 +90,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={t('ceph-storage-plugin~Key Management Service Provider')}
className="ocs-install-encryption__form-body"
className={`${className}__form-body`}
>
<FormSelect
value={kmsProvider}
Expand All @@ -108,7 +112,7 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
<FormGroup
fieldId="kms-service-name"
label={t('ceph-storage-plugin~Service Name')}
className="ocs-install-encryption__form-body"
className={`${className}__form-body`}
helperTextInvalid="This is a required field"
validated={isValid(kms.name.valid)}
isRequired
Expand All @@ -127,7 +131,7 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
<FormGroup
fieldId="kms-address"
label={t('ceph-storage-plugin~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={isValid(kms.address.valid)}
isRequired
Expand All @@ -146,7 +150,10 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
<FormGroup
fieldId="kms-address-port"
label={t('ceph-storage-plugin~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={isValid(kms.port.valid)}
isRequired
Expand All @@ -162,29 +169,27 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
/>
</FormGroup>
</div>
<FormGroup
fieldId="kms-token"
label={t('ceph-storage-plugin~Token')}
className="ocs-install-encryption__form-body"
helperTextInvalid={t('ceph-storage-plugin~This is a required field')}
validated={isValid(kms.token.valid)}
isRequired
>
<TextInput
value={kms.token.value}
onChange={setToken}
type="password"
id="kms-token"
name="kms-token"
isRequired
{mode && (
<FormGroup
fieldId="kms-token"
label={t('ceph-storage-plugin~Token')}
className={`${className}__form-body`}
helperTextInvalid={t('ceph-storage-plugin~This is a required field')}
validated={isValid(kms.token.valid)}
/>
</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={isValid(kms.token.valid)}
/>
</FormGroup>
)}
<Button variant="link" className={`${className}__form-body`} onClick={openAdvancedModal}>
{t('ceph-storage-plugin~Advanced Settings')}{' '}
{(kms.backend ||
kms.caCert ||
Expand All @@ -200,7 +205,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,19 @@
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 {
CEPH_STORAGE_NAMESPACE,
MODES,
KMSConfigMapName,
KMSSecretName,
KMSConfigMapCSIName,
} 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,24 +23,71 @@ export const parseURL = (url: string) => {
}
};

export const createKmsResources = (kms: KMSConfig) => {
const tokenSecret: SecretKind = {
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
name: KMSSecretName,
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
data: kms.token.value,
},
};
export const generateCASecret = (caCertificate: string) => ({
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
name: `ocs-kms-ca-secret-${Math.random()
.toString(36)
.substring(7)}`,
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-${Math.random()
.toString(36)
.substring(7)}`,
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-${Math.random()
.toString(36)
.substring(7)}`,
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
'tls.key': clientKey,
},
});

export const createKmsResources = (kms: KMSConfig, update = false, previousData?: any) => {
let tokenSecret: SecretKind;
if (kms.token) {
tokenSecret = {
apiVersion: SecretModel.apiVersion,
kind: SecretModel.kind,
metadata: {
name: KMSSecretName,
namespace: CEPH_STORAGE_NAMESPACE,
},
stringData: {
data: kms.token.value,
},
};
}

const resources: Promise<K8sResourceKind>[] = [];

const parsedAddress = parseURL(kms.address.value);

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 All @@ -42,6 +96,7 @@ export const createKmsResources = (kms: KMSConfig) => {
VAULT_CLIENT_KEY: kms.clientKey?.metadata.name,
VAULT_NAMESPACE: kms.providerNamespace,
};

const configMapObj: ConfigMapKind = {
apiVersion: ConfigMapModel.apiVersion,
kind: ConfigMapModel.kind,
Expand All @@ -54,6 +109,34 @@ export const createKmsResources = (kms: KMSConfig) => {
},
};

const csiConfigData: 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,
VAULT_TLS_SERVER_NAME: kms.tls,
VAULT_CLIENT_CERT: kms.clientCert?.metadata.name,
VAULT_CLIENT_KEY: kms.clientKey?.metadata.name,
VAULT_NAMESPACE: kms.providerNamespace,
VAULT_TOKEN_NAME: KMSSecretName,
VAULT_CACERT_FILE: kms.caCertFile,
VAULT_CLIENT_CERT_FILE: kms.clientCertFile,
VAULT_CLIENT_KEY_FILE: kms.clientKeyFile,
};

const csiConfigObj: ConfigMapKind = {
apiVersion: ConfigMapModel.apiVersion,
kind: ConfigMapModel.kind,
data: {
[`1-${kms.name.value}`]: JSON.stringify(csiConfigData),
},
metadata: {
name: KMSConfigMapCSIName,
namespace: CEPH_STORAGE_NAMESPACE,
},
};

if (kms.caCert) {
resources.push(k8sCreate(SecretModel, kms.caCert, CEPH_STORAGE_NAMESPACE));
}
Expand All @@ -66,15 +149,29 @@ export const createKmsResources = (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 patchValue = Object.keys(previousData).length + 1;
const cmPatch = [
{
op: 'replace',
path: `/data/${patchValue}-${kms.name.value}`,
value: JSON.stringify(csiConfigData),
},
];
resources.push(k8sPatch(ConfigMapModel, csiConfigObj, cmPatch));
} else {
resources.push(k8sCreate(SecretModel, tokenSecret, CEPH_STORAGE_NAMESPACE));
resources.push(k8sCreate(ConfigMapModel, configMapObj, CEPH_STORAGE_NAMESPACE));
resources.push(k8sCreate(ConfigMapModel, csiConfigObj, 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

0 comments on commit 081ff72

Please sign in to comment.