Fixes and improvements for Tenant Security page (#2252)

- Tenant securityContext was only being applied to first pool
- Fixed style issues on tenant security page to be more consistent
- Added missing FsGroupChangePolicy in the SecurityContextSelector
  component

Signed-off-by: Lenin Alevski <alevsk.8772@gmail.com>
This commit is contained in:
Lenin Alevski
2022-08-29 13:35:23 -07:00
committed by GitHub
parent b7783aaa1c
commit 139771f4d4
10 changed files with 447 additions and 222 deletions

View File

@@ -1096,8 +1096,13 @@ func updateTenantSecurity(ctx context.Context, operatorClient OperatorClientI, c
// set Security Context
var newTenantSecurityContext *corev1.PodSecurityContext
newTenantSecurityContext, _ = convertModelSCToK8sSC(params.Body.SecurityContext)
minInst.Spec.Pools[0].SecurityContext = newTenantSecurityContext
newTenantSecurityContext, err = convertModelSCToK8sSC(params.Body.SecurityContext)
if err != nil {
return err
}
for index := range minInst.Spec.Pools {
minInst.Spec.Pools[index].SecurityContext = newTenantSecurityContext
}
// Update External Certificates
minInst.Spec.ExternalCertSecret = newMinIOExternalCertSecret

View File

@@ -58,8 +58,10 @@ func convertModelSCToK8sSC(sc *models.SecurityContext) (*corev1.PodSecurityConte
if err != nil {
return nil, err
}
FSGroupChangePolicy := corev1.PodFSGroupChangePolicy(sc.FsGroupChangePolicy)
FSGroupChangePolicy := corev1.PodFSGroupChangePolicy("Always")
if sc.FsGroupChangePolicy != "" {
FSGroupChangePolicy = corev1.PodFSGroupChangePolicy(sc.FsGroupChangePolicy)
}
return &corev1.PodSecurityContext{
RunAsUser: &runAsUser,
RunAsGroup: &runAsGroup,
@@ -74,10 +76,10 @@ func convertK8sSCToModelSC(sc *corev1.PodSecurityContext) *models.SecurityContex
runAsUser := strconv.FormatInt(*sc.RunAsUser, 10)
runAsGroup := strconv.FormatInt(*sc.RunAsGroup, 10)
fsGroup := strconv.FormatInt(*sc.FSGroup, 10)
fsGroupPolicy := ""
fsGroupChangePolicy := "Always"
if sc.FSGroupChangePolicy != nil {
fsGroupPolicy = string(*sc.FSGroupChangePolicy)
fsGroupChangePolicy = string(*sc.FSGroupChangePolicy)
}
return &models.SecurityContext{
@@ -85,7 +87,7 @@ func convertK8sSCToModelSC(sc *corev1.PodSecurityContext) *models.SecurityContex
RunAsGroup: &runAsGroup,
RunAsNonRoot: sc.RunAsNonRoot,
FsGroup: fsGroup,
FsGroupChangePolicy: fsGroupPolicy,
FsGroupChangePolicy: fsGroupChangePolicy,
}
}

View File

@@ -62,6 +62,8 @@ import {
} from "../TenantDetails/tenantMonitoringSlice";
import { clearValidationError, imagePattern, numericPattern } from "../utils";
import SecurityContextSelector from "../securityContextSelector";
import { setFSGroupChangePolicy } from "../tenantSecurityContextSlice";
import { fsGroupChangePolicyType } from "../types";
interface ITenantMonitoring {
classes: any;
@@ -150,6 +152,10 @@ const TenantMonitoring = ({ classes }: ITenantMonitoring) => {
const runAsNonRoot = useSelector(
(state: AppState) => state.editTenantMonitoring.runAsNonRoot
);
const fsGroupChangePolicy = useSelector(
(state: AppState) => state.editTenantSecurityContext.fsGroupChangePolicy
);
const cleanValidation = (fieldName: string) => {
setValidationErrors(clearValidationError(validationErrors, fieldName));
};
@@ -551,12 +557,16 @@ const TenantMonitoring = ({ classes }: ITenantMonitoring) => {
runAsUser={runAsUser}
fsGroup={fsGroup}
runAsNonRoot={runAsNonRoot}
fsGroupChangePolicy={fsGroupChangePolicy}
setFSGroup={(value: string) => dispatch(setFSGroup(value))}
setRunAsUser={(value: string) => dispatch(setRunAsUser(value))}
setRunAsGroup={(value: string) => dispatch(setRunAsGroup(value))}
setRunAsNonRoot={(value: boolean) =>
dispatch(setRunAsNonRoot(value))
}
setFSGroupChangePolicy={(value: fsGroupChangePolicyType) =>
dispatch(setFSGroupChangePolicy(value))
}
/>
</Grid>
<Grid item xs={12} textAlign={"right"}>

View File

@@ -50,14 +50,16 @@ import {
setDBMemRequest,
setDBRunAsUser,
setDBFSGroup,
setDBFSGroupChangePolicy,
setDBRunAsGroup,
setDBRunAsNonRoot,
setRefreshLoggingInfo,
} from "../TenantDetails/tenantAuditLogSlice";
} from "./tenantAuditLogSlice";
import SecurityContextSelector from "../securityContextSelector";
import { clearValidationError, imagePattern, numericPattern } from "../utils";
import { fsGroupChangePolicyType } from "../types";
const styles = (theme: Theme) =>
createStyles({
@@ -116,6 +118,10 @@ const LoggingDBDetails = ({
const dbFSGroup = useSelector(
(state: AppState) => state.editTenantLogging.dbSecurityContext.fsGroup
);
const dbFSGroupChangePolicy = useSelector(
(state: AppState) =>
state.editTenantLogging.dbSecurityContext.fsGroupChangePolicy
);
const dbRunAsNonRoot = useSelector(
(state: AppState) => state.editTenantLogging.dbSecurityContext.runAsNonRoot
);
@@ -178,6 +184,8 @@ const LoggingDBDetails = ({
runAsUser: dbRunAsUser != null ? dbRunAsUser : "",
fsGroup: dbFSGroup != null ? dbFSGroup : "",
runAsNonRoot: dbRunAsNonRoot != null ? dbRunAsNonRoot : true,
fsGroupChangePolicy:
dbFSGroupChangePolicy != null ? dbFSGroupChangePolicy : "Always",
};
api
.invoke(
@@ -328,6 +336,7 @@ const LoggingDBDetails = ({
runAsGroup={dbRunAsGroup}
runAsUser={dbRunAsUser}
fsGroup={dbFSGroup}
fsGroupChangePolicy={dbFSGroupChangePolicy}
runAsNonRoot={dbRunAsNonRoot}
setFSGroup={(value: string) => dispatch(setDBFSGroup(value))}
setRunAsUser={(value: string) => dispatch(setDBRunAsUser(value))}
@@ -335,6 +344,9 @@ const LoggingDBDetails = ({
setRunAsNonRoot={(value: boolean) =>
dispatch(setDBRunAsNonRoot(value))
}
setFSGroupChangePolicy={(value: fsGroupChangePolicyType) =>
dispatch(setDBFSGroupChangePolicy(value))
}
/>
</Grid>
<Grid item xs={12} textAlign={"right"}>

View File

@@ -57,6 +57,8 @@ import {
setRunAsNonRoot,
setRefreshLoggingInfo,
} from "../TenantDetails/tenantAuditLogSlice";
import { setFSGroupChangePolicy } from "../tenantSecurityContextSlice";
import { fsGroupChangePolicyType } from "../types";
const styles = (theme: Theme) =>
createStyles({
@@ -118,6 +120,9 @@ const TenantAuditLogging = ({
const runAsNonRoot = useSelector(
(state: AppState) => state.editTenantLogging.securityContext.runAsNonRoot
);
const fsGroupChangePolicy = useSelector(
(state: AppState) => state.editTenantSecurityContext.fsGroupChangePolicy
);
const [validationErrors, setValidationErrors] = useState<any>({});
const [loading, setLoading] = useState<boolean>(false);
@@ -332,12 +337,16 @@ const TenantAuditLogging = ({
runAsUser={runAsUser}
fsGroup={fsGroup}
runAsNonRoot={runAsNonRoot}
fsGroupChangePolicy={fsGroupChangePolicy}
setFSGroup={(value: string) => dispatch(setFSGroup(value))}
setRunAsUser={(value: string) => dispatch(setRunAsUser(value))}
setRunAsGroup={(value: string) => dispatch(setRunAsGroup(value))}
setRunAsNonRoot={(value: boolean) =>
dispatch(setRunAsNonRoot(value))
}
setFSGroupChangePolicy={(value: fsGroupChangePolicyType) =>
dispatch(setFSGroupChangePolicy(value))
}
/>
</Grid>

View File

@@ -17,11 +17,15 @@
import React, { Fragment, useCallback, useEffect, useState } from "react";
import { connect, useSelector } from "react-redux";
import { Theme } from "@mui/material/styles";
import { Button, DialogContentText } from "@mui/material";
import { Button, DialogContentText, IconButton } from "@mui/material";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import Grid from "@mui/material/Grid";
import { ICertificateInfo, ITenantSecurityResponse } from "../types";
import {
fsGroupChangePolicyType,
ICertificateInfo,
ITenantSecurityResponse,
} from "../types";
import {
containerForHeader,
createTenantCommon,
@@ -50,7 +54,9 @@ import {
setFSGroup,
setRunAsGroup,
setRunAsNonRoot,
setFSGroupChangePolicy,
} from "../tenantSecurityContextSlice";
import RemoveIcon from "../../../../icons/RemoveIcon";
interface ITenantSecurity {
classes: any;
@@ -60,6 +66,55 @@ const styles = (theme: Theme) =>
createStyles({
...tenantDetailsStyles,
...spacingUtils,
minioCertificateRows: {
display: "flex",
alignItems: "center",
justifyContent: "flex-start",
borderBottom: "1px solid #EAEAEA",
"&:last-child": {
borderBottom: 0,
},
"@media (max-width: 900px)": {
flex: 1,
},
},
minioCertsContainer: {
marginBottom: 15,
},
minioCACertsRow: {
display: "flex",
alignItems: "center",
justifyContent: "flex-start",
borderBottom: "1px solid #EAEAEA",
"&:last-child": {
borderBottom: 0,
},
"@media (max-width: 900px)": {
flex: 1,
"& div label": {
minWidth: 50,
},
},
},
rowActions: {
display: "flex",
justifyContent: "flex-end",
"@media (max-width: 900px)": {
flex: 1,
},
},
overlayAction: {
marginLeft: 10,
"& svg": {
maxWidth: 15,
maxHeight: 15,
},
"& button": {
background: "#EAEAEA",
},
},
loaderAlign: {
textAlign: "center",
},
@@ -93,14 +148,31 @@ const TenantSecurity = ({ classes }: ITenantSecurity) => {
const [isSending, setIsSending] = useState<boolean>(false);
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
const [enableTLS, setEnableTLS] = useState<boolean>(false);
const [enableAutoCert, setEnableAutoCert] = useState<boolean>(false);
const [enableCustomCerts, setEnableCustomCerts] = useState<boolean>(false);
const [certificatesToBeRemoved, setCertificatesToBeRemoved] = useState<
string[]
>([]);
// MinIO certificates
const [minioCertificates, setMinioCertificates] = useState<KeyPair[]>([]);
const [minioCaCertificates, setMinioCaCertificates] = useState<KeyPair[]>([]);
const [minioCertificates, setMinioCertificates] = useState<KeyPair[]>([
{
id: Date.now().toString(),
key: "",
cert: "",
encoded_key: "",
encoded_cert: "",
},
]);
const [minioCaCertificates, setMinioCaCertificates] = useState<KeyPair[]>([
{
id: Date.now().toString(),
key: "",
cert: "",
encoded_key: "",
encoded_cert: "",
},
]);
const [minioTLSCertificateSecrets, setMinioTLSCertificateSecrets] = useState<
ICertificateInfo[]
>([]);
@@ -119,6 +191,9 @@ const TenantSecurity = ({ classes }: ITenantSecurity) => {
const runAsNonRoot = useSelector(
(state: AppState) => state.editTenantSecurityContext.runAsNonRoot
);
const fsGroupChangePolicy = useSelector(
(state: AppState) => state.editTenantSecurityContext.fsGroupChangePolicy
);
const getTenantSecurityInfo = useCallback(() => {
api
@@ -128,8 +203,10 @@ const TenantSecurity = ({ classes }: ITenantSecurity) => {
)
.then((res: ITenantSecurityResponse) => {
setEnableAutoCert(res.autoCert);
setEnableTLS(res.autoCert);
if (res.customCertificates.minio || res.customCertificates.minioCAs) {
setEnableCustomCerts(true);
setEnableTLS(true);
}
setMinioTLSCertificateSecrets(res.customCertificates.minio || []);
setMinioTLSCaCertificateSecrets(res.customCertificates.minioCAs || []);
@@ -137,6 +214,9 @@ const TenantSecurity = ({ classes }: ITenantSecurity) => {
dispatch(setRunAsUser(res.securityContext.runAsUser));
dispatch(setFSGroup(res.securityContext.fsGroup));
dispatch(setRunAsNonRoot(res.securityContext.runAsNonRoot));
dispatch(
setFSGroupChangePolicy(res.securityContext.fsGroupChangePolicy)
);
})
.catch((err: ErrorResponseHandler) => {
dispatch(setErrorSnackMessage(err));
@@ -159,6 +239,7 @@ const TenantSecurity = ({ classes }: ITenantSecurity) => {
runAsUser: runAsUser,
runAsNonRoot: runAsNonRoot,
fsGroup: fsGroup,
fsGroupChangePolicy: fsGroupChangePolicy,
},
};
if (enableCustomCerts) {
@@ -361,212 +442,253 @@ const TenantSecurity = ({ classes }: ITenantSecurity) => {
<h1 className={classes.sectionTitle}>Security</h1>
<hr className={classes.hrClass} />
</Grid>
<Grid item xs={12}>
<FormSwitchWrapper
value="enableAutoCert"
id="enableAutoCert"
name="enableAutoCert"
checked={enableAutoCert}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
setEnableAutoCert(checked);
}}
label={"TLS"}
description={
"The internode certificates will be generated and managed by MinIO Operator"
}
/>
</Grid>
<Grid item xs={12}>
<FormSwitchWrapper
value="enableCustomCerts"
id="enableCustomCerts"
name="enableCustomCerts"
checked={enableCustomCerts}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
setEnableCustomCerts(checked);
}}
label={"Custom Certificates"}
description={"Certificates used to terminated TLS at MinIO"}
/>
</Grid>
<Grid container spacing={1}>
<Grid item xs={12}>
<FormSwitchWrapper
value="enableTLS"
id="enableTLS"
name="enableTLS"
checked={enableTLS}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
setEnableTLS(checked);
}}
label={"TLS"}
description={
"Securing all the traffic using TLS. This is required for Encryption Configuration"
}
/>
</Grid>
{enableTLS && (
<Fragment>
<Grid item xs={12} className={classes.formFieldRow}>
<FormSwitchWrapper
value="enableAutoCert"
id="enableAutoCert"
name="enableAutoCert"
checked={enableAutoCert}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
setEnableAutoCert(checked);
}}
label={"AutoCert"}
description={
"The internode certificates will be generated and managed by MinIO Operator"
}
/>
</Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<FormSwitchWrapper
value="enableCustomCerts"
id="enableCustomCerts"
name="enableCustomCerts"
checked={enableCustomCerts}
onChange={(e) => {
const targetD = e.target;
const checked = targetD.checked;
setEnableCustomCerts(checked);
}}
label={"Custom Certificates"}
description={"Certificates used to terminated TLS at MinIO"}
/>
</Grid>
{enableCustomCerts && (
<Fragment>
<Grid item xs={12}>
<SectionTitle>MinIO Certificates</SectionTitle>
</Grid>
<Grid item xs={12}>
{minioTLSCertificateSecrets.map(
(certificateInfo: ICertificateInfo) => (
<TLSCertificate
certificateInfo={certificateInfo}
onDelete={() => removeCertificate(certificateInfo)}
/>
)
{enableCustomCerts && (
<Fragment>
<Grid item xs={12} className={classes.formFieldRow}>
<SectionTitle>MinIO Certificates</SectionTitle>
</Grid>
<Grid item xs={12}>
{minioTLSCertificateSecrets.map(
(certificateInfo: ICertificateInfo) => (
<TLSCertificate
certificateInfo={certificateInfo}
onDelete={() => removeCertificate(certificateInfo)}
/>
)
)}
</Grid>
<Grid item xs={12} className={classes.formFieldRow}>
{minioCertificates.map((keyPair, index) => (
<Grid
item
xs={12}
key={keyPair.id}
className={classes.minioCertificateRows}
>
<Grid item xs={10} className={classes.fileItem}>
<FileSelector
onChange={(encodedValue, fileName) =>
addFileToKeyPair(
"minio",
keyPair.id,
"cert",
fileName,
encodedValue
)
}
accept=".cer,.crt,.cert,.pem"
id="tlsCert"
name="tlsCert"
label="Cert"
value={keyPair.cert}
/>
<FileSelector
onChange={(encodedValue, fileName) =>
addFileToKeyPair(
"minio",
keyPair.id,
"key",
fileName,
encodedValue
)
}
accept=".key,.pem"
id="tlsKey"
name="tlsKey"
label="Key"
value={keyPair.key}
/>
</Grid>
<Grid item xs={2} className={classes.rowActions}>
<div className={classes.overlayAction}>
<IconButton
size={"small"}
onClick={() => addKeyPair("minio")}
disabled={
index !== minioCertificates.length - 1
}
>
<AddIcon />
</IconButton>
</div>
<div className={classes.overlayAction}>
<IconButton
size={"small"}
onClick={() =>
deleteKeyPair("minio", keyPair.id)
}
disabled={minioCertificates.length <= 1}
>
<RemoveIcon />
</IconButton>
</div>
</Grid>
</Grid>
))}
</Grid>
<Grid item xs={12}>
<SectionTitle>MinIO CA Certificates</SectionTitle>
</Grid>
<Grid item xs={12}>
{minioTLSCaCertificateSecrets.map(
(certificateInfo: ICertificateInfo) => (
<TLSCertificate
certificateInfo={certificateInfo}
onDelete={() => removeCertificate(certificateInfo)}
/>
)
)}
</Grid>
<Grid item xs={12}>
{minioCaCertificates.map((keyPair: KeyPair, index) => (
<Grid
item
xs={12}
key={keyPair.id}
className={classes.minioCACertsRow}
>
<Grid item xs={10}>
<FileSelector
onChange={(encodedValue, fileName) =>
addFileToKeyPair(
"minioCAs",
keyPair.id,
"cert",
fileName,
encodedValue
)
}
accept=".cer,.crt,.cert,.pem"
id="tlsCert"
name="tlsCert"
label="Cert"
value={keyPair.cert}
/>
</Grid>
<Grid item xs={2}>
<div className={classes.rowActions}>
<div className={classes.overlayAction}>
<IconButton
size={"small"}
onClick={() => addKeyPair("minioCAs")}
disabled={
index !== minioCaCertificates.length - 1
}
>
<AddIcon />
</IconButton>
</div>
<div className={classes.overlayAction}>
<IconButton
size={"small"}
onClick={() =>
deleteKeyPair("minioCAs", keyPair.id)
}
disabled={minioCaCertificates.length <= 1}
>
<RemoveIcon />
</IconButton>
</div>
</div>
</Grid>
</Grid>
))}
</Grid>
</Fragment>
)}
</Grid>
<Grid item xs={12}>
{minioCertificates.map((keyPair) => (
<Grid
container
key={keyPair.id}
alignItems={"center"}
style={{ borderBottom: "1px solid #eaeaea" }}
>
<Grid item xs={5}>
<FileSelector
onChange={(encodedValue, fileName) =>
addFileToKeyPair(
"minio",
keyPair.id,
"cert",
fileName,
encodedValue
)
}
accept=".cer,.crt,.cert,.pem"
id="tlsCert"
name="tlsCert"
label="Cert"
value={keyPair.cert}
/>
</Grid>
<Grid item xs={5}>
<FileSelector
onChange={(encodedValue, fileName) =>
addFileToKeyPair(
"minio",
keyPair.id,
"key",
fileName,
encodedValue
)
}
accept=".key,.pem"
id="tlsKey"
name="tlsKey"
label="Key"
value={keyPair.key}
/>
</Grid>
<Grid item xs={2}>
<Button
variant="outlined"
color="secondary"
onClick={() => deleteKeyPair("minio", keyPair.id)}
>
Remove
</Button>
</Grid>
</Grid>
))}
</Grid>
<Grid item xs={12} textAlign={"right"}>
<Button
variant="outlined"
color="primary"
endIcon={<AddIcon />}
onClick={() => addKeyPair("minio")}
>
Add Certificate
</Button>
</Grid>
<Grid item xs={12}>
<SectionTitle>MinIO CA Certificates</SectionTitle>
</Grid>
<Grid item xs={12}>
{minioTLSCaCertificateSecrets.map(
(certificateInfo: ICertificateInfo) => (
<TLSCertificate
certificateInfo={certificateInfo}
onDelete={() => removeCertificate(certificateInfo)}
/>
)
)}
</Grid>
<Grid item xs={12}>
{minioCaCertificates.map((keyPair: KeyPair) => (
<Grid
container
key={keyPair.id}
style={{ borderBottom: "1px solid #eaeaea" }}
alignItems={"center"}
justifyContent={"space-between"}
>
<Grid item xs={5} className={classes.fileItem}>
<FileSelector
onChange={(encodedValue, fileName) =>
addFileToKeyPair(
"minioCAs",
keyPair.id,
"cert",
fileName,
encodedValue
)
}
accept=".cer,.crt,.cert,.pem"
id="tlsCert"
name="tlsCert"
label="Cert"
value={keyPair.cert}
/>
</Grid>
<Grid item xs={2}>
<Button
variant="outlined"
color="secondary"
onClick={() => deleteKeyPair("minioCAs", keyPair.id)}
>
Remove
</Button>
</Grid>
</Grid>
))}
</Grid>
<Grid item xs={12} textAlign={"right"}>
<Button
variant="outlined"
color="primary"
endIcon={<AddIcon />}
onClick={() => addKeyPair("minioCAs")}
>
Add CA Certificate
</Button>
</Grid>
</Fragment>
)}
<Grid item xs={12} className={classes.formFieldRow}>
<SecurityContextSelector
classes={classes}
runAsGroup={runAsGroup}
runAsUser={runAsUser}
fsGroup={fsGroup}
runAsNonRoot={runAsNonRoot}
setFSGroup={(value: string) => dispatch(setFSGroup(value))}
setRunAsUser={(value: string) => dispatch(setRunAsUser(value))}
setRunAsGroup={(value: string) => dispatch(setRunAsGroup(value))}
setRunAsNonRoot={(value: boolean) =>
dispatch(setRunAsNonRoot(value))
}
/>
</Grid>
<Grid item xs={12} textAlign={"right"}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={dialogOpen || isSending}
onClick={() => setDialogOpen(true)}
>
Save
</Button>
</Fragment>
)}
<Grid item xs={12} className={classes.formFieldRow}>
<h1 className={classes.sectionTitle}>Security Context</h1>
<hr className={classes.hrClass} />
</Grid>
<Grid item xs={12} className={classes.formFieldRow}>
<SecurityContextSelector
classes={classes}
runAsGroup={runAsGroup}
runAsUser={runAsUser}
fsGroup={fsGroup}
runAsNonRoot={runAsNonRoot}
fsGroupChangePolicy={fsGroupChangePolicy}
setFSGroup={(value: string) => dispatch(setFSGroup(value))}
setRunAsUser={(value: string) => dispatch(setRunAsUser(value))}
setRunAsGroup={(value: string) =>
dispatch(setRunAsGroup(value))
}
setRunAsNonRoot={(value: boolean) =>
dispatch(setRunAsNonRoot(value))
}
setFSGroupChangePolicy={(value: fsGroupChangePolicyType) =>
dispatch(setFSGroupChangePolicy(value))
}
/>
</Grid>
<Grid item xs={12} textAlign={"right"}>
<Button
type="submit"
variant="contained"
color="primary"
disabled={dialogOpen || isSending}
onClick={() => setDialogOpen(true)}
>
Save
</Button>
</Grid>
</Grid>
</Grid>
)}

View File

@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { IKeyValue } from "../ListTenants/types";
import { ISecurityContext } from "../types";
import { fsGroupChangePolicyType, ISecurityContext } from "../types";
export interface IEditTenantAuditLogging {
auditLoggingEnabled: boolean;
@@ -151,6 +151,12 @@ export const editTenantAuditLoggingSlice = createSlice({
setDBFSGroup: (state, action: PayloadAction<string>) => {
state.dbSecurityContext.fsGroup = action.payload;
},
setDBFSGroupChangePolicy: (
state,
action: PayloadAction<fsGroupChangePolicyType>
) => {
state.dbSecurityContext.fsGroupChangePolicy = action.payload;
},
setDBRunAsNonRoot: (state, action: PayloadAction<boolean>) => {
state.dbSecurityContext.runAsNonRoot = action.payload;
},
@@ -185,6 +191,7 @@ export const {
setRunAsNonRoot,
setDBRunAsUser,
setDBFSGroup,
setDBFSGroupChangePolicy,
setDBRunAsGroup,
setDBRunAsNonRoot,
setRefreshLoggingInfo,

View File

@@ -17,30 +17,51 @@
import React, { Fragment } from "react";
import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWrapper";
import FormSwitchWrapper from "../Common/FormComponents/FormSwitchWrapper/FormSwitchWrapper";
import { Grid } from "@mui/material";
import SelectWrapper from "../Common/FormComponents/SelectWrapper/SelectWrapper";
import { Grid, SelectChangeEvent } from "@mui/material";
import { useDispatch } from "react-redux";
import { Theme } from "@mui/material/styles";
import createStyles from "@mui/styles/createStyles";
import withStyles from "@mui/styles/withStyles";
import { fsGroupChangePolicyType } from "./types";
interface IEditSecurityContextProps {
classes: any;
runAsUser: string;
runAsGroup: string;
fsGroup: string;
fsGroupChangePolicy: fsGroupChangePolicyType;
runAsNonRoot: boolean;
setRunAsUser: any;
setRunAsGroup: any;
setFSGroup: any;
setRunAsNonRoot: any;
setFSGroupChangePolicy: any;
}
const styles = (theme: Theme) =>
createStyles({
configSectionItem: {
marginRight: 15,
marginBottom: 15,
"& .multiContainer": {
border: "1px solid red",
},
},
});
const SecurityContextSelector = ({
classes,
runAsGroup,
runAsUser,
fsGroup,
fsGroupChangePolicy,
runAsNonRoot,
setRunAsUser,
setRunAsGroup,
setFSGroup,
setRunAsNonRoot,
setFSGroupChangePolicy,
}: IEditSecurityContextProps) => {
const dispatch = useDispatch();
return (
@@ -78,6 +99,10 @@ const SecurityContextSelector = ({
min="0"
/>
</div>
</div>
</Grid>
<Grid item xs={12}>
<div className={`${classes.multiContainerStackNarrow} `}>
<div className={classes.configSectionItem}>
<InputBoxWrapper
type="number"
@@ -92,9 +117,30 @@ const SecurityContextSelector = ({
min="0"
/>
</div>
<div className={classes.configSectionItem}>
<SelectWrapper
label="FsGroupChangePolicy"
id="securityContext_fsGroupChangePolicy"
name="securityContext_fsGroupChangePolicy"
onChange={(e: SelectChangeEvent<string>) => {
dispatch(setFSGroupChangePolicy(e.target.value));
}}
value={fsGroupChangePolicy}
options={[
{
label: "Always",
value: "Always",
},
{
label: "OnRootMismatch",
value: "OnRootMismatch",
},
]}
/>
</div>
</div>
</Grid>
<br />
<Grid item xs={12}>
<div className={classes.multiContainer}>
<FormSwitchWrapper
@@ -113,4 +159,5 @@ const SecurityContextSelector = ({
</Fragment>
);
};
export default SecurityContextSelector;
export default withStyles(styles)(SecurityContextSelector);

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { IEditTenantSecurityContext } from "./types";
import { fsGroupChangePolicyType, IEditTenantSecurityContext } from "./types";
const initialState: IEditTenantSecurityContext = {
securityContextEnabled: false,
@@ -22,6 +22,7 @@ const initialState: IEditTenantSecurityContext = {
runAsGroup: "1000",
fsGroup: "1000",
runAsNonRoot: true,
fsGroupChangePolicy: "Always",
};
export const editTenantSecurityContextSlice = createSlice({
@@ -43,6 +44,12 @@ export const editTenantSecurityContextSlice = createSlice({
setRunAsNonRoot: (state, action: PayloadAction<boolean>) => {
state.runAsNonRoot = action.payload;
},
setFSGroupChangePolicy: (
state,
action: PayloadAction<fsGroupChangePolicyType>
) => {
state.fsGroupChangePolicy = action.payload;
},
},
});
@@ -52,6 +59,7 @@ export const {
setRunAsGroup,
setFSGroup,
setRunAsNonRoot,
setFSGroupChangePolicy,
} = editTenantSecurityContextSlice.actions;
export default editTenantSecurityContextSlice.reducer;

View File

@@ -132,12 +132,14 @@ export interface LabelKeyPair {
value: string;
}
export type fsGroupChangePolicyType = "Always" | "OnRootMismatch";
export interface ISecurityContext {
runAsUser: string;
runAsGroup: string;
runAsNonRoot: boolean;
fsGroup: string;
fsGroupChangePolicy: "Always" | "OnRootMismatch";
fsGroupChangePolicy: fsGroupChangePolicyType;
}
export interface IConfigureFields {
@@ -360,5 +362,6 @@ export interface IEditTenantSecurityContext {
runAsUser: string;
runAsGroup: string;
fsGroup: string;
fsGroupChangePolicy: fsGroupChangePolicyType;
runAsNonRoot: boolean;
}