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 3, 2020
1 parent e9bbb1f commit dc41d5a
Show file tree
Hide file tree
Showing 11 changed files with 585 additions and 97 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 @@ -82,10 +84,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 @@ -103,7 +106,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={isValid(kms.name.valid)}
isRequired
Expand All @@ -122,7 +125,7 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
<FormGroup
fieldId="kms-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={isValid(kms.address.valid)}
isRequired
Expand All @@ -141,7 +144,10 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
<FormGroup
fieldId="kms-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={isValid(kms.port.valid)}
isRequired
Expand All @@ -157,29 +163,27 @@ export const KMSConfigure: React.FC<KMSConfigureProps> = ({ state, dispatch, mod
/>
</FormGroup>
</div>
<FormGroup
fieldId="kms-token"
label="Token"
className="ocs-install-encryption__form-body"
helperTextInvalid="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"
{mode && (
<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}
isRequired
validated={isValid(kms.token.valid)}
/>
</FormGroup>
<Button
variant="link"
className="ocs-install-encryption__form-body"
onClick={openAdvancedModal}
>
>
<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 @@ -195,7 +199,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,65 @@ 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',
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 createKmsResources = (kms: KMSConfig, update = false) => {
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 +90,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 +103,31 @@ 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,
};

const csiConfigObj: ConfigMapKind = {
apiVersion: ConfigMapModel.apiVersion,
kind: ConfigMapModel.kind,
data: {
[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 +140,28 @@ 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 cmPatch = [
{
op: 'add',
path: `/data/${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 dc41d5a

Please sign in to comment.