Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CA issue prerequisites #1673

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions locales/en/plugin__odf-console.json
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,10 @@
"Search a bucket by name": "Search a bucket by name",
"Create bucket": "Create bucket",
"Browse, upload, and manage objects in buckets.": "Browse, upload, and manage objects in buckets.",
"Could not load information": "Could not load information",
"The browser cannot connect securely to this endpoint because it does not recognize the SSL certificate. This occurs when the certificate of the endpoint is not issued by a trusted Certificate Authority (CA).": "The browser cannot connect securely to this endpoint because it does not recognize the SSL certificate. This occurs when the certificate of the endpoint is not issued by a trusted Certificate Authority (CA).",
"To establish a connection with the endpoint, try the following methods:": "To establish a connection with the endpoint, try the following methods:",
"<0><0>1. Recommended:</0> Replace the internal certificate with one issued by a public or custom Certificate Authority (CA). See the <3>OpenShift documentation</3> for guidance.<6></6><7>2. Alternative method:</7> Add the internal CA bundle of OpenShift Container Platform to the trust store of your system. This ensures that the browser recognises the internal certificate. <10>(<1>ConfigMap:</1> default-ingress-cert in <3>Namespace:</3> openshift-config-managed)</10>.<12></12><13>3. Temporary (Least recommended):</13> Open the endpoint in a new tab (<15>click here to open the S3 route</15>) and click <17>Continue to site</17> (wording may vary by browser) to bypass the security warning. Then refresh the Data Foundation tab.</0>": "<0><0>1. Recommended:</0> Replace the internal certificate with one issued by a public or custom Certificate Authority (CA). See the <3>OpenShift documentation</3> for guidance.<6></6><7>2. Alternative method:</7> Add the internal CA bundle of OpenShift Container Platform to the trust store of your system. This ensures that the browser recognises the internal certificate. <10>(<1>ConfigMap:</1> default-ingress-cert in <3>Namespace:</3> openshift-config-managed)</10>.<12></12><13>3. Temporary (Least recommended):</13> Open the endpoint in a new tab (<15>click here to open the S3 route</15>) and click <17>Continue to site</17> (wording may vary by browser) to bypass the security warning. Then refresh the Data Foundation tab.</0>",
"Create Bucket": "Create Bucket",
"An object bucket is a cloud storage container that organizes and manages files (objects), allowing users to store, retrieve and control access to data efficiently.": "An object bucket is a cloud storage container that organizes and manages files (objects), allowing users to store, retrieve and control access to data efficiently.",
"Select bucket creation method": "Select bucket creation method",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
ConfigMapKind,
ConfigMapModel,
GreenCheckCircleIcon,
TimesCircleIcon,
RedTimesIcon,
} from '@odf/shared';
import { StorageClusterKind } from '@odf/shared/types';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
Expand All @@ -30,7 +30,7 @@ type EncryptionPopoverProps = {
};

const StatusIcon: React.FC<{ enabled: boolean }> = ({ enabled }) =>
enabled ? <GreenCheckCircleIcon /> : <TimesCircleIcon />;
enabled ? <GreenCheckCircleIcon /> : <RedTimesIcon />;

const getKmsTypeDescription = (encryptionKMSType: string, t: TFunction) => {
let provider = '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,24 @@ import { Button, ButtonVariant, Flex, FlexItem } from '@patternfly/react-core';
import { SyncAltIcon } from '@patternfly/react-icons';
import { BUCKET_CREATE_PAGE_PATH } from '../../../constants';
import { BucketCrFormat } from '../../../types';
import { isCAError, CAErrorMessage } from '../ca-error/CAErrorMessage';
import { NoobaaS3Provider } from '../noobaa-context';
import { BucketsListTable } from './bucketListTable';
import { BucketPagination } from './bucketPagination';

const BucketsListPageBody: React.FC = () => {
type BucketInfo = [BucketCrFormat[], boolean, any];

type BucketsListPageBodyProps = {
bucketInfo: BucketInfo;
setBucketInfo: React.Dispatch<React.SetStateAction<BucketInfo>>;
};

const BucketsListPageBody: React.FC<BucketsListPageBodyProps> = ({
bucketInfo,
setBucketInfo,
}) => {
const { t } = useCustomTranslation();
const [fresh, triggerRefresh] = useRefresh();
const [bucketInfo, setBucketInfo] = React.useState<
[BucketCrFormat[], boolean, any]
>([[], false, undefined]);
const [buckets, loaded, loadError] = bucketInfo;
const [allBuckets, filteredBuckets, onFilterChange] =
useListPageFilter(buckets);
Expand Down Expand Up @@ -69,11 +77,21 @@ const BucketsListPageBody: React.FC = () => {
);
};

const BucketsListPage: React.FC = () => {
const BucketsListPageContent: React.FC = () => {
const { t } = useCustomTranslation();
const [bucketInfo, setBucketInfo] = React.useState<BucketInfo>([
[],
false,
undefined,
]);
const [_buckets, _loaded, loadError] = bucketInfo;

if (isCAError(loadError)) {
return <CAErrorMessage />;
}

return (
<NoobaaS3Provider loading={false}>
<>
<ListPageHeader title={t('Buckets')}>
<ListPageCreateLink to={BUCKET_CREATE_PAGE_PATH}>
{t('Create bucket')}
Expand All @@ -82,7 +100,18 @@ const BucketsListPage: React.FC = () => {
<div className="pf-v5-u-ml-lg pf-v5-u-mr-lg text-muted">
{t('Browse, upload, and manage objects in buckets.')}
</div>
<BucketsListPageBody />
<BucketsListPageBody
bucketInfo={bucketInfo}
setBucketInfo={setBucketInfo}
/>
</>
);
};

const BucketsListPage: React.FC = () => {
return (
<NoobaaS3Provider loading={false}>
<BucketsListPageContent />
</NoobaaS3Provider>
);
};
Expand Down
91 changes: 91 additions & 0 deletions packages/odf/components/s3-browser/ca-error/CAErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as React from 'react';
import { NoobaaS3Context } from '@odf/core/components/s3-browser/noobaa-context';
import { RedTimesCircleIcon } from '@odf/shared';
import { DOC_VERSION } from '@odf/shared/hooks';
import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook';
import { ExternalLink } from '@odf/shared/utils';
import { Trans } from 'react-i18next';
import {
EmptyState,
EmptyStateHeader,
EmptyStateBody,
EmptyStateIcon,
EmptyStateVariant,
} from '@patternfly/react-core';

const customCADocLink = (docVersion: string) =>
`https://docs.openshift.com/container-platform/${docVersion}/security/certificates/replacing-default-ingress-certificate.html`;

// In a browser environment, the error objects returned by AWS SDK do not include granular information about TLS or certificate-specific issues.
// Hence relying on error "name" and "message" content.
export const isCAError = (error: Error) => {
const errorMessage = error?.message.toLowerCase();
const errorType = error?.name;
if (
['TypeError', 'NetworkingError', 'NetworkError'].includes(errorType) &&
(errorMessage.includes('certificate') ||
errorMessage.includes('authority') ||
errorMessage.includes('ssl') ||
errorMessage.includes('tls') ||
errorMessage.includes('self-signed') ||
errorMessage.includes('self signed') ||
errorMessage.includes('failed to fetch') ||
errorMessage.includes('load failed') ||
errorMessage.includes('network'))
)
return true;
return false;
};

export const CAErrorMessage: React.FC = () => {
const { t } = useCustomTranslation();
const { noobaaS3Route } = React.useContext(NoobaaS3Context);

return (
<>
<EmptyState variant={EmptyStateVariant.lg}>
<EmptyStateHeader
titleText={t('Could not load information')}
icon={<EmptyStateIcon icon={RedTimesCircleIcon} />}
headingLevel="h4"
/>
<EmptyStateBody>
{t(
'The browser cannot connect securely to this endpoint because it does not recognize the SSL certificate. This occurs when the certificate of the endpoint is not issued by a trusted Certificate Authority (CA).'
)}
<p className="pf-v5-u-mt-lg">
{t(
'To establish a connection with the endpoint, try the following methods:'
)}
</p>
</EmptyStateBody>
</EmptyState>
<Trans>
<div className="text-muted pf-v5-u-ml-4xl pf-v5-u-mr-4xl">
<b>1. Recommended:</b> Replace the internal certificate with one
issued by a public or custom Certificate Authority (CA). See the{' '}
<ExternalLink href={customCADocLink(DOC_VERSION)}>
OpenShift documentation
</ExternalLink>{' '}
for guidance.
<br />
<b>2. Alternative method:</b> Add the internal CA bundle of OpenShift
Container Platform to the trust store of your system. This ensures
that the browser recognises the internal certificate.{' '}
<i>
(<b>ConfigMap:</b> default-ingress-cert in <b>Namespace:</b>{' '}
openshift-config-managed)
</i>
.<br />
<b>3. Temporary (Least recommended):</b> Open the endpoint in a new
tab (
<ExternalLink href={noobaaS3Route}>
click here to open the S3 route
</ExternalLink>
) and click <b>Continue to site</b> (wording may vary by browser) to
bypass the security warning. Then refresh the Data Foundation tab.
</div>
</Trans>
</>
);
};
14 changes: 11 additions & 3 deletions packages/odf/components/s3-browser/noobaa-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {

type NoobaaS3ContextType = {
noobaaS3: S3Commands;
noobaaS3Route: string;
};

type NoobaaS3ProviderType = {
Expand Down Expand Up @@ -44,16 +45,21 @@ export const NoobaaS3Provider: React.FC<NoobaaS3ProviderType> = ({
NOOBAA_S3_ROUTE
);

const s3Route = React.useRef<string>();

const [noobaaS3, noobaaS3Error]: [S3Commands, unknown] = React.useMemo(() => {
if (!_.isEmpty(secretData) && !_.isEmpty(routeData)) {
try {
const endpoint = `https://${routeData.spec.host}`;
s3Route.current = `https://${routeData.spec.host}`;
const accessKeyId = atob(secretData.data?.[NOOBAA_ACCESS_KEY_ID]);
const secretAccessKey = atob(
secretData.data?.[NOOBAA_SECRET_ACCESS_KEY]
);

return [new S3Commands(endpoint, accessKeyId, secretAccessKey), null];
return [
new S3Commands(s3Route.current, accessKeyId, secretAccessKey),
null,
];
} catch (err) {
return [{} as S3Commands, err];
}
Expand All @@ -71,7 +77,9 @@ export const NoobaaS3Provider: React.FC<NoobaaS3ProviderType> = ({
odfNsLoadError || secretError || routeError || noobaaS3Error || error;

return allLoaded && !anyError ? (
<NoobaaS3Context.Provider value={{ noobaaS3 }}>
<NoobaaS3Context.Provider
value={{ noobaaS3, noobaaS3Route: s3Route.current }}
>
{children}
</NoobaaS3Context.Provider>
) : (
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/src/constants/doc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const ODF_DEFAULT_DOC_VERSION = '4.16';
export const ACM_DEFAULT_DOC_VERSION = '2.10';
alfonsomthd marked this conversation as resolved.
Show resolved Hide resolved
export const ODF_DEFAULT_DOC_VERSION = '4.18';
export const ACM_DEFAULT_DOC_VERSION = '2.12';

export const odfDocHome = (odfDocVersion) =>
`https://access.redhat.com/documentation/en-us/red_hat_openshift_data_foundation/${odfDocVersion}`;
Expand Down
14 changes: 13 additions & 1 deletion packages/shared/src/status/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
ResourcesAlmostFullIcon,
ResourcesFullIcon,
TimesIcon,
TimesCircleIcon,
} from '@patternfly/react-icons';

export type ColoredIconProps = {
Expand Down Expand Up @@ -146,9 +147,20 @@ export const BlueArrowCircleUpIcon: React.FC<ColoredIconProps> = ({
/>
);

export const TimesCircleIcon: React.FC<ColoredIconProps> = ({
export const RedTimesIcon: React.FC<ColoredIconProps> = ({
className,
title,
}) => (
<TimesIcon color={dangerColor.value} className={className} title={title} />
);

export const RedTimesCircleIcon: React.FC<ColoredIconProps> = ({
className,
title,
}) => (
<TimesCircleIcon
color={dangerColor.value}
className={className}
title={title}
/>
);
Loading