|
|
@@ -1,7 +1,7 @@
|
|
|
-import React, { useContext, useEffect, useMemo, useState } from "react";
|
|
|
import type { JsonValue } from "@bufbuild/protobuf";
|
|
|
import { Cluster, Contract, EKS, EKSLogging } from "@porter-dev/api-contracts";
|
|
|
import axios from "axios";
|
|
|
+import React, { useContext, useEffect, useMemo, useState } from "react";
|
|
|
import styled from "styled-components";
|
|
|
import { match } from "ts-pattern";
|
|
|
|
|
|
@@ -13,9 +13,10 @@ import Spacer from "components/porter/Spacer";
|
|
|
import Text from "components/porter/Text";
|
|
|
import ToggleRow from "components/porter/ToggleRow";
|
|
|
|
|
|
-import api from "shared/api";
|
|
|
-import { Context } from "shared/Context";
|
|
|
import sparkle from "assets/sparkle.svg";
|
|
|
+import SOC2Checks from "components/SOC2Checks";
|
|
|
+import { Context } from "shared/Context";
|
|
|
+import api from "shared/api";
|
|
|
|
|
|
type Props = {
|
|
|
credentialId: string;
|
|
|
@@ -23,6 +24,51 @@ type Props = {
|
|
|
selectedClusterVersion: JsonValue;
|
|
|
};
|
|
|
|
|
|
+
|
|
|
+// Example SOC2 Check NOTE PLEASE ADD FUNC TO createContract and useEffect(() to correctly READ AND WRITE
|
|
|
+// "Display_Name_Of_SOC2_Check": {
|
|
|
+// "message": "Main Example Message about the Check",
|
|
|
+// "link": "example link for more docs ",
|
|
|
+// "enabled": (false or true if porter does it by default),
|
|
|
+// "status": ""(Keep blank or ENABLED if porter does it by default)
|
|
|
+// "enabledField": "text that goes next to the toggle",
|
|
|
+// "info": " more information",
|
|
|
+// "locked":(true if unmutable field like KMS),
|
|
|
+// "disabledTooltip": "display if message is disabled",
|
|
|
+// "hideToggle": true (if you want to hide the toggle
|
|
|
+//}
|
|
|
+const soc2DataDefault = {
|
|
|
+ "soc2_checks": {
|
|
|
+ "Public SSH Access": {
|
|
|
+ "message": "Porter-provisioned instances do not allow remote SSH access. Users are not allowed to invoke commands directly on the host, and all commands are invoked via the EKS Control Plane.",
|
|
|
+ "enabled": true,
|
|
|
+ "hideToggle": true,
|
|
|
+ "status": "ENABLED"
|
|
|
+ },
|
|
|
+ "Cluster Secret Encryption": {
|
|
|
+ "message": "Cluster secrets can be encrypted using an AWS KMS Key. Secrets will be encrypted at rest, and encryption cannot be disabled for secrets.",
|
|
|
+ "enabled": false,
|
|
|
+ "disabledTooltip": "Enable KMS encryption for the cluster to enable SOC 2 compliance.",
|
|
|
+ "link": "https://aws.amazon.com/about-aws/whats-new/2020/03/amazon-eks-adds-envelope-encryption-for-secrets-with-aws-kms/",
|
|
|
+ "locked": true,
|
|
|
+ "status": "",
|
|
|
+ },
|
|
|
+ "Control Plane Log Retention": {
|
|
|
+ "message": "EKS Control Plane logs are by default available for a minimal amount of time, typically 1 hour or less. EKS CloudTrail Forwarding automatically sends control plane logs to CloudTrail for longer retention and later inspection.",
|
|
|
+ "enabled": false,
|
|
|
+ "enabledField": "Retain CloudTrail logs for 365 days",
|
|
|
+ "status": "",
|
|
|
+ },
|
|
|
+ "Enhanced Image Vulnerability Scanning": {
|
|
|
+ "message": "AWS ECR scans for CVEs from the open-source Clair database on push image push. Enhanced scanning provides continuous, automated scans against images as new vulnerabilities appear.",
|
|
|
+ "link": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning-enhanced.html",
|
|
|
+ "enabled": false,
|
|
|
+ "info": "",
|
|
|
+ "status": ""
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
const DEFAULT_ERROR_MESSAGE =
|
|
|
"An error occurred while provisioning your infrastructure. Please try again.";
|
|
|
|
|
|
@@ -30,17 +76,14 @@ const Compliance: React.FC<Props> = (props) => {
|
|
|
const { currentProject, currentCluster, setShouldRefreshClusters } =
|
|
|
useContext(Context);
|
|
|
|
|
|
- const [cloudTrailEnabled, setCloudTrailEnabled] = useState(false);
|
|
|
- // const [cloudTrailRetention, setCloudTrailRetention] = useState(false);
|
|
|
- const [ecrScanningEnabled, setEcrScanningEnabled] = useState(false);
|
|
|
- const [isReadOnly, setIsReadOnly] = useState(false);
|
|
|
const [isClicked, setIsClicked] = useState(false);
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
- const [kmsEnabled, setKmsEnabled] = useState(false);
|
|
|
const [soc2Enabled, setSoc2Enabled] = useState(false);
|
|
|
const [clusterRegion, setClusterRegion] = useState("");
|
|
|
const [errorMessage, setErrorMessage] = useState<string>("");
|
|
|
const [errorDetails, setErrorDetails] = useState<string>("");
|
|
|
+ const [soc2Data, setSoc2Data] = useState(soc2DataDefault);
|
|
|
+ const [isReadOnly, setIsReadOnly] = useState(false);
|
|
|
|
|
|
const applySettings = async (): Promise<void> => {
|
|
|
if (!currentCluster || !currentProject || !setShouldRefreshClusters) {
|
|
|
@@ -102,6 +145,11 @@ const Compliance: React.FC<Props> = (props) => {
|
|
|
};
|
|
|
|
|
|
const createContract = (base64Contract: string): Contract => {
|
|
|
+ //
|
|
|
+ const cloudTrailEnabled = soc2Data.soc2_checks["Control Plane Log Retention"].enabled
|
|
|
+ const kmsEnabled = soc2Data.soc2_checks["Cluster Secret Encryption"].enabled
|
|
|
+ const ecrScanningEnabled = soc2Data.soc2_checks["Control Plane Log Retention"].enabled
|
|
|
+
|
|
|
const contractData = JSON.parse(atob(base64Contract));
|
|
|
const latestCluster: Cluster = Cluster.fromJson(contractData.cluster, {
|
|
|
ignoreUnknownFields: true,
|
|
|
@@ -202,13 +250,24 @@ const Compliance: React.FC<Props> = (props) => {
|
|
|
project_id: currentProject ? currentProject.id : 0,
|
|
|
}
|
|
|
);
|
|
|
- } catch (err) {}
|
|
|
+ } catch (err) { }
|
|
|
};
|
|
|
|
|
|
const isUserProvisioning = useMemo(() => {
|
|
|
return isReadOnly && props.provisionerError === "";
|
|
|
}, [isReadOnly, props.provisionerError]);
|
|
|
|
|
|
+ const determineStatus = (enabled: boolean): string => {
|
|
|
+ if (enabled) {
|
|
|
+ if (currentCluster?.status === "UPDATING") {
|
|
|
+ return "PENDING"
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return "ENABLED"
|
|
|
+ }
|
|
|
+ return ""
|
|
|
+ }
|
|
|
+
|
|
|
useEffect(() => {
|
|
|
const contract: Contract = Contract.fromJson(props.selectedClusterVersion, {
|
|
|
ignoreUnknownFields: true,
|
|
|
@@ -223,15 +282,36 @@ const Compliance: React.FC<Props> = (props) => {
|
|
|
eksValues.logging.enableAuthenticatorLogs &&
|
|
|
eksValues.logging.enableControllerManagerLogs;
|
|
|
|
|
|
- setCloudTrailEnabled(cloudTrailEnabled);
|
|
|
setClusterRegion(eksValues.region);
|
|
|
- setEcrScanningEnabled(eksValues.enableEcrScanning);
|
|
|
- setKmsEnabled(eksValues.enableKmsEncryption);
|
|
|
+
|
|
|
+ setSoc2Data(prevSoc2Data => {
|
|
|
+ return {
|
|
|
+ ...prevSoc2Data,
|
|
|
+ soc2_checks: {
|
|
|
+ ...prevSoc2Data.soc2_checks,
|
|
|
+ "Control Plane Log Retention": {
|
|
|
+ ...prevSoc2Data.soc2_checks["Control Plane Log Retention"],
|
|
|
+ enabled: cloudTrailEnabled,
|
|
|
+ status: determineStatus(cloudTrailEnabled)
|
|
|
+ },
|
|
|
+ "Cluster Secret Encryption": {
|
|
|
+ ...prevSoc2Data.soc2_checks["Cluster Secret Encryption"],
|
|
|
+ enabled: eksValues.enableKmsEncryption,
|
|
|
+ status: determineStatus(eksValues.enableKmsEncryption)
|
|
|
+ },
|
|
|
+ "Enhanced Image Vulnerability Scanning": {
|
|
|
+ ...prevSoc2Data.soc2_checks["Enhanced Image Vulnerability Scanning"],
|
|
|
+ enabled: eksValues.enableEcrScanning,
|
|
|
+ status: determineStatus(eksValues.enableEcrScanning)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ });
|
|
|
|
|
|
setSoc2Enabled(
|
|
|
cloudTrailEnabled &&
|
|
|
- eksValues.enableKmsEncryption &&
|
|
|
- eksValues.enableEcrScanning
|
|
|
+ eksValues.enableKmsEncryption &&
|
|
|
+ eksValues.enableEcrScanning
|
|
|
);
|
|
|
}
|
|
|
}, [props.selectedClusterVersion]);
|
|
|
@@ -243,18 +323,10 @@ const Compliance: React.FC<Props> = (props) => {
|
|
|
|
|
|
setIsReadOnly(
|
|
|
currentCluster.status === "UPDATING" ||
|
|
|
- currentCluster.status === "UPDATING_UNAVAILABLE"
|
|
|
+ currentCluster.status === "UPDATING_UNAVAILABLE"
|
|
|
);
|
|
|
}, []);
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- if (soc2Enabled) {
|
|
|
- setCloudTrailEnabled(true);
|
|
|
- // setCloudTrailRetention(true);
|
|
|
- setEcrScanningEnabled(true);
|
|
|
- setKmsEnabled(true);
|
|
|
- }
|
|
|
- }, [soc2Enabled]);
|
|
|
return (
|
|
|
<StyledCompliance>
|
|
|
<Spacer y={1} />
|
|
|
@@ -266,115 +338,38 @@ const Compliance: React.FC<Props> = (props) => {
|
|
|
New
|
|
|
</NewBadge>
|
|
|
</Container>
|
|
|
- <Spacer y={0.5} />
|
|
|
- <Text color="helper">
|
|
|
- Configure your AWS infrastructure to be SOC 2 compliant with Porter.
|
|
|
- </Text>
|
|
|
- <Spacer y={0.5} />
|
|
|
- <ToggleRow
|
|
|
- isToggled={soc2Enabled}
|
|
|
- onToggle={() => {
|
|
|
- setSoc2Enabled((prev) => !prev);
|
|
|
- }}
|
|
|
- disabled={isReadOnly}
|
|
|
- disabledTooltip={
|
|
|
- "Wait for provisioning to complete before editing this field."
|
|
|
- }
|
|
|
- >
|
|
|
- <Container row>
|
|
|
- <Text>Enable all SOC 2 settings</Text>
|
|
|
- </Container>
|
|
|
- </ToggleRow>
|
|
|
- <Spacer y={0.5} />
|
|
|
- <GutterContainer>
|
|
|
- <ToggleRow
|
|
|
- isToggled={cloudTrailEnabled}
|
|
|
- onToggle={() => {
|
|
|
- setCloudTrailEnabled((prev) => !prev);
|
|
|
- }}
|
|
|
- disabled={soc2Enabled || isReadOnly}
|
|
|
- disabledTooltip={
|
|
|
- soc2Enabled
|
|
|
- ? "Global SOC 2 setting must be disabled to toggle this"
|
|
|
- : "Wait for provisioning to complete before editing this field."
|
|
|
- }
|
|
|
- >
|
|
|
- <Container row>
|
|
|
- <Text>EKS CloudTrail Forwarding</Text>
|
|
|
- <Spacer inline x={1} />
|
|
|
- <Text color="helper">
|
|
|
- Forward all application and control plane logs to CloudTrail.
|
|
|
- </Text>
|
|
|
- </Container>
|
|
|
- </ToggleRow>
|
|
|
- {/* <Spacer y={0.5} />
|
|
|
- <ToggleRow
|
|
|
- isToggled={cloudTrailRetention}
|
|
|
- onToggle={() => { setCloudTrailRetention((prev) => !prev) }}
|
|
|
- disabled={soc2Enabled || isReadOnly}
|
|
|
- disabledTooltip={
|
|
|
- soc2Enabled ? "Global SOC 2 setting must be disabled to toggle this" : "Wait for provisioning to complete before editing this field."
|
|
|
- }
|
|
|
- >
|
|
|
- <Container row>
|
|
|
- <Text>Retain CloudTrail logs for 365 days</Text>
|
|
|
- <Spacer inline x={1} />
|
|
|
- <Text color="helper">Store CloudTrail logs in an S3 bucket for 365 days.</Text>
|
|
|
- </Container>
|
|
|
- </ToggleRow> */}
|
|
|
- <Spacer y={0.5} />
|
|
|
- <ToggleRow
|
|
|
- isToggled={kmsEnabled}
|
|
|
- onToggle={() => {
|
|
|
- setKmsEnabled((prev) => !prev);
|
|
|
- }}
|
|
|
- disabled={soc2Enabled || isReadOnly || kmsEnabled}
|
|
|
- disabledTooltip={
|
|
|
- kmsEnabled
|
|
|
- ? "KMS encryption can never be disabled."
|
|
|
- : soc2Enabled
|
|
|
- ? "Global SOC 2 setting must be disabled to toggle this"
|
|
|
- : "Wait for provisioning to complete before editing this field."
|
|
|
- }
|
|
|
+
|
|
|
+ <SOC2Checks
|
|
|
+ enableAll={soc2Enabled}
|
|
|
+ soc2Data={soc2Data}
|
|
|
+ setSoc2Data={setSoc2Data}
|
|
|
+ readOnly={isReadOnly}
|
|
|
+ />
|
|
|
+ <Spacer y={1} />
|
|
|
+ <Container row >
|
|
|
+ <Button
|
|
|
+ disabled={isDisabled() ?? isLoading}
|
|
|
+ onClick={applySettings}
|
|
|
+ status={getStatus()}
|
|
|
>
|
|
|
- <Container row>
|
|
|
- <Text>AWS KMS Secret Encryption</Text>
|
|
|
- <Spacer inline x={1} />
|
|
|
- <Text color="helper">
|
|
|
- Encrypt secrets with AWS Key Management Service.
|
|
|
- </Text>
|
|
|
- </Container>
|
|
|
- </ToggleRow>
|
|
|
- <Spacer y={0.5} />
|
|
|
+ Save settings
|
|
|
+ </Button>
|
|
|
+ <Spacer inline x={1} />
|
|
|
<ToggleRow
|
|
|
- isToggled={ecrScanningEnabled}
|
|
|
+ isToggled={soc2Enabled}
|
|
|
onToggle={() => {
|
|
|
- setEcrScanningEnabled((prev) => !prev);
|
|
|
+ setSoc2Enabled((prev) => !prev);
|
|
|
}}
|
|
|
- disabled={soc2Enabled || isReadOnly}
|
|
|
+ disabled={isReadOnly}
|
|
|
disabledTooltip={
|
|
|
- soc2Enabled
|
|
|
- ? "Global SOC 2 setting must be disabled to toggle this"
|
|
|
- : "Wait for provisioning to complete before editing this field."
|
|
|
+ "Wait for provisioning to complete before editing this field."
|
|
|
}
|
|
|
>
|
|
|
<Container row>
|
|
|
- <Text>Enhanced ECR scanning</Text>
|
|
|
- <Spacer inline x={1} />
|
|
|
- <Text color="helper">
|
|
|
- Scan ECR image repositories for vulnerabilities.
|
|
|
- </Text>
|
|
|
+ <Text>Enable All</Text>
|
|
|
</Container>
|
|
|
</ToggleRow>
|
|
|
- </GutterContainer>
|
|
|
- <Spacer y={1} />
|
|
|
- <Button
|
|
|
- disabled={isDisabled() ?? isLoading}
|
|
|
- onClick={applySettings}
|
|
|
- status={getStatus()}
|
|
|
- >
|
|
|
- Save settings
|
|
|
- </Button>
|
|
|
+ </Container>
|
|
|
</StyledCompliance>
|
|
|
);
|
|
|
};
|
|
|
@@ -383,12 +378,6 @@ export default Compliance;
|
|
|
|
|
|
const StyledCompliance = styled.div``;
|
|
|
|
|
|
-const GutterContainer = styled.div`
|
|
|
- border-left: 1px solid #313237;
|
|
|
- margin-left: 5px;
|
|
|
- padding-left: 15px;
|
|
|
-`;
|
|
|
-
|
|
|
const NewBadge = styled.div`
|
|
|
font-size: 13px;
|
|
|
padding: 5px 10px;
|
|
|
@@ -401,4 +390,4 @@ const NewBadge = styled.div`
|
|
|
height: 14px;
|
|
|
margin-right: 5px;
|
|
|
}
|
|
|
-`;
|
|
|
+`;
|