Skip to content

Commit

Permalink
Merge pull request #13642 from rhamilto/ocpbugs-25274
Browse files Browse the repository at this point in the history
[release-4.14] OCPBUGS-25274: Add support for Azure Workload Identity / Federated Identity based in…
  • Loading branch information
openshift-merge-bot[bot] committed Mar 4, 2024
2 parents c636042 + 84b86a2 commit c5c6009
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@
"Container image": "Container image",
"Cluster in STS Mode": "Cluster in STS Mode",
"This cluster is using AWS Security Token Service to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, you will need to provide a role ARN (with an attached policy) during installation. Please see the operator description for more details.": "This cluster is using AWS Security Token Service to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, you will need to provide a role ARN (with an attached policy) during installation. Please see the operator description for more details.",
"Cluster in Azure Workload Identity / Federated Identity Mode": "Cluster in Azure Workload Identity / Federated Identity Mode",
"This cluster is using Azure Workload Identity / Federated Identity to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, provide the Client ID, Tenant ID, and Subscription ID during installation. See the operator description for more details.": "This cluster is using Azure Workload Identity / Federated Identity to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, provide the Client ID, Tenant ID, and Subscription ID during installation. See the operator description for more details.",
"Installed": "Installed",
"Not Installed": "Not Installed",
"provided by {{provider}}": "provided by {{provider}}",
Expand Down Expand Up @@ -318,8 +320,15 @@
"Operator Installation": "Operator Installation",
"Install your Operator by subscribing to one of the update channels to keep the Operator up to date. The strategy determines either manual or automatic updates.": "Install your Operator by subscribing to one of the update channels to keep the Operator up to date. The strategy determines either manual or automatic updates.",
"This cluster is using AWS Security Token Service to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, you will need to provide a role ARN (with an attached policy) during installation. Manual subscriptions are highly recommended as steps should be taken prior to upgrade to ensure that the permissions required by the next version are properly accounted for in the role. Please see the operator description for more details.": "This cluster is using AWS Security Token Service to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, you will need to provide a role ARN (with an attached policy) during installation. Manual subscriptions are highly recommended as steps should be taken prior to upgrade to ensure that the permissions required by the next version are properly accounted for in the role. Please see the operator description for more details.",
"This cluster is using Azure Workload Identity / Federated Identity to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, provide the Client ID, Tenant ID, and Subscription ID during installation. Manual subscriptions are highly recommended as steps should be taken before upgrade to ensure that the permissions required by the next version are properly accounted for in the role. See the operator description for more details.": "This cluster is using Azure Workload Identity / Federated Identity to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, provide the Client ID, Tenant ID, and Subscription ID during installation. Manual subscriptions are highly recommended as steps should be taken before upgrade to ensure that the permissions required by the next version are properly accounted for in the role. See the operator description for more details.",
"role ARN": "role ARN",
"The role ARN required for the operator to access the cloud API.": "The role ARN required for the operator to access the cloud API.",
"Azure Client ID": "Azure Client ID",
"The Azure Client ID required for the operator to access the cloud API.": "The Azure Client ID required for the operator to access the cloud API.",
"Azure Tenant ID": "Azure Tenant ID",
"The Azure Tenant ID required for the operator to access the cloud API.": "The Azure Tenant ID required for the operator to access the cloud API.",
"Azure Subscription ID": "Azure Subscription ID",
"The Azure Subscription ID required for the operator to access the cloud API.": "The Azure Subscription ID required for the operator to access the cloud API.",
"Update channel": "Update channel",
"The channel to track and receive the updates from.": "The channel to track and receive the updates from.",
"Installation mode": "Installation mode",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export enum InfraFeatures {
csi = 'Container Storage Interface',
sno = 'Single Node Clusters',
// eslint-disable-next-line @typescript-eslint/naming-convention
'Short-lived token authentication' = 'Short-lived token authentication',
TokenAuth = 'Short-lived token authentication',
}

export enum ValidSubscriptionValue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { ClusterServiceVersionKind, SubscriptionKind } from '../../types';
import { MarkdownView } from '../clusterserviceversion';
import { defaultChannelNameFor } from '../index';
import { OperatorChannelSelect, OperatorVersionSelect } from './operator-channel-version-select';
import { shortLivedTokenAuth, isAWSSTSCluster } from './operator-hub-utils';
import { isAWSSTSCluster, isAzureWIFCluster } from './operator-hub-utils';
import { InfraFeatures, OperatorHubItem } from './index';

// t('olm~Basic Install'),
Expand Down Expand Up @@ -363,7 +363,7 @@ export const OperatorHubItemDetails: React.FC<OperatorHubItemDetailsProps> = ({
<div className="co-catalog-page__overlay-description">
{isAWSSTSCluster(cloudCredentials, infrastructure, authentication) &&
showWarn &&
infraFeatures?.find((i) => i === InfraFeatures[shortLivedTokenAuth]) && (
infraFeatures?.find((i) => i === InfraFeatures.TokenAuth) && (
<Alert
isInline
variant="warning"
Expand All @@ -378,6 +378,23 @@ export const OperatorHubItemDetails: React.FC<OperatorHubItemDetailsProps> = ({
</p>
</Alert>
)}
{isAzureWIFCluster(cloudCredentials, infrastructure, authentication) &&
showWarn &&
infraFeatures?.find((i) => i === InfraFeatures.TokenAuth) && (
<Alert
isInline
variant="warning"
title={t('olm~Cluster in Azure Workload Identity / Federated Identity Mode')}
actionClose={<AlertActionCloseButton onClose={() => setShowWarn(false)} />}
className="pf-u-mb-lg"
>
<p>
{t(
'olm~This cluster is using Azure Workload Identity / Federated Identity to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, provide the Client ID, Tenant ID, and Subscription ID during installation. See the operator description for more details.',
)}
</p>
</Alert>
)}
<OperatorHubItemDetailsHintBlock
installed={installed}
isInstalling={isInstalling}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { DefaultCatalogSource, DefaultCatalogSourceDisplayName } from '../../con
import { SubscriptionModel } from '../../models';
import { communityOperatorWarningModal } from './operator-hub-community-provider-modal';
import { OperatorHubItemDetails } from './operator-hub-item-details';
import { isAWSSTSCluster, shortLivedTokenAuth } from './operator-hub-utils';
import { isAWSSTSCluster, isAzureWIFCluster } from './operator-hub-utils';
import {
OperatorHubItem,
InstalledState,
Expand Down Expand Up @@ -217,7 +217,7 @@ const infraFeaturesSort = (infrastructure) => {
return 1;
case InfraFeatures.FipsMode:
return 2;
case InfraFeatures[shortLivedTokenAuth]:
case InfraFeatures.TokenAuth:
return 3;
default:
return 4;
Expand Down Expand Up @@ -426,10 +426,21 @@ export const OperatorHubTileView: React.FC<OperatorHubTileViewProps> = (props) =
currentItem.infrastructure,
currentItem.authentication,
) &&
currentItem.infraFeatures?.find((i) => i === InfraFeatures[shortLivedTokenAuth])
currentItem.infraFeatures?.find((i) => i === InfraFeatures.TokenAuth)
) {
setTokenizedAuth('AWS');
}
if (
currentItem &&
isAzureWIFCluster(
currentItem.cloudCredentials,
currentItem.infrastructure,
currentItem.authentication,
) &&
currentItem.infraFeatures?.find((i) => i === InfraFeatures.TokenAuth)
) {
setTokenizedAuth('Azure');
}
}, [filteredItems]);

const showCommunityOperator = (item: OperatorHubItem) => (ignoreWarning = false) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ import { subscriptionFor } from '../operator-group';
import { OperatorHubTileView } from './operator-hub-items';
import {
getCatalogSourceDisplayName,
shortLivedTokenAuth,
isAWSSTSCluster,
isAzureWIFCluster,
} from './operator-hub-utils';
import {
OperatorHubItem,
Expand Down Expand Up @@ -168,8 +168,8 @@ export const OperatorHubList: React.FC<OperatorHubListProps> = ({
// tlsProfiles requires addtional changes
// [OperatorHubCSVAnnotationKey.tlsProfiles]: tlsProfiles,
[OperatorHubCSVAnnotationKey.tokenAuthAWS]: tokenAuthAWS,
// tokenAuthAzure and tokenAuthGCP require additional changes
// [OperatorHubCSVAnnotationKey.tokenAuthAzure]: tokenAuthAzure,
[OperatorHubCSVAnnotationKey.tokenAuthAzure]: tokenAuthAzure,
// tokenAuthGCP requires additional changes
// [OperatorHubCSVAnnotationKey.tokenAuthGCP]: tokenAuthGCP,
[OperatorHubCSVAnnotationKey.actionText]: marketplaceActionText,
[OperatorHubCSVAnnotationKey.remoteWorkflow]: marketplaceRemoteWorkflow,
Expand All @@ -185,10 +185,12 @@ export const OperatorHubList: React.FC<OperatorHubListProps> = ({

const auth = loaded && authentication?.data;

// old infra feature annotation
let infrastructureFeatures: InfraFeatures[] = parsedInfraFeatures.map(
(key) => InfraFeatures[key],
);

// new infra feature annotation
const featuresAnnotationsObjects = [
{ key: InfraFeatures.Disconnected, value: disconnected },
{ key: InfraFeatures.FipsMode, value: fipsCompliant },
Expand All @@ -198,6 +200,7 @@ export const OperatorHubList: React.FC<OperatorHubListProps> = ({
{ key: InfraFeatures.csi, value: csi },
];

// override old with new
featuresAnnotationsObjects.forEach(({ key, value }) => {
if (value === 'false') {
// override existing operators.openshift.io/infrastructure-features annotation value
Expand All @@ -208,7 +211,9 @@ export const OperatorHubList: React.FC<OperatorHubListProps> = ({
});

if (tokenAuthAWS === 'true' && isAWSSTSCluster(cloudCredential, infra, auth)) {
infrastructureFeatures.push(InfraFeatures[shortLivedTokenAuth]);
infrastructureFeatures.push(InfraFeatures.TokenAuth);
} else if (tokenAuthAzure === 'true' && isAzureWIFCluster(cloudCredential, infra, auth)) {
infrastructureFeatures.push(InfraFeatures.TokenAuth);
}

const infraFeatures = _.uniq(_.compact(infrastructureFeatures));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
const { provider, channels = [], packageName, catalogSource, catalogSourceNamespace } =
packageManifest?.status ?? {};

const [roleARNText, setRoleARNText] = React.useState(null);
const [roleARNText, setRoleARNText] = React.useState('');
const [azureTenantId, setAzureTenantId] = React.useState('');
const [azureClientId, setAzureClientId] = React.useState('');
const [azureSubscriptionId, setAzureSubscriptionId] = React.useState('');
const { catalogNamespace, channel, pkg, tokenizedAuth, version } = getURLSearchParams();
const [targetNamespace, setTargetNamespace] = React.useState(null);
const [installMode, setInstallMode] = React.useState(null);
Expand Down Expand Up @@ -254,7 +257,8 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
if (
version !== currentLatestVersion ||
manualSubscriptionsInNamespace?.length > 0 ||
tokenizedAuth === 'AWS'
tokenizedAuth === 'AWS' ||
tokenizedAuth === 'Azure'
) {
setApproval(InstallPlanApproval.Manual);
} else setApproval(InstallPlanApproval.Automatic);
Expand Down Expand Up @@ -417,15 +421,37 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
},
};

if (tokenizedAuth === 'AWS') {
subscription.spec.config = {
env: [
{
name: 'ROLEARN',
value: roleARNText,
},
],
};
switch (tokenizedAuth) {
case 'AWS':
subscription.spec.config = {
env: [
{
name: 'ROLEARN',
value: roleARNText,
},
],
};
break;
case 'Azure':
subscription.spec.config = {
env: [
{
name: 'CLIENTID',
value: azureClientId,
},
{
name: 'TENANTID',
value: azureTenantId,
},
{
name: 'SUBSCRIPTIONID',
value: azureSubscriptionId,
},
],
};
break;
default:
break;
}

try {
Expand Down Expand Up @@ -475,7 +501,9 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
!namespaceSupports(selectedTargetNamespace)(selectedInstallMode) ||
(selectedTargetNamespace && cannotResolve) ||
!_.isEmpty(conflictingProvidedAPIs(selectedTargetNamespace)) ||
(tokenizedAuth === 'AWS' && _.isNull(roleARNText));
(tokenizedAuth === 'AWS' && _.isEmpty(roleARNText)) ||
(tokenizedAuth === 'Azure' &&
[azureClientId, azureTenantId, azureSubscriptionId].some((v) => _.isEmpty(v)));

const formError = () => {
return (
Expand Down Expand Up @@ -609,7 +637,9 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
id="enable-monitoring-checkbox"
data-test="enable-monitoring"
label={t('olm~Enable Operator recommended cluster monitoring on this Namespace')}
onChange={setEnableMonitoring}
onChange={(value) => {
setEnableMonitoring(value);
}}
isChecked={enableMonitoring}
data-checked-state={enableMonitoring}
/>
Expand Down Expand Up @@ -754,6 +784,21 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
</p>
</Alert>
)}
{tokenizedAuth === 'Azure' && showSTSWarn && (
<Alert
isInline
variant="warning"
title={t('olm~Cluster in Azure Workload Identity / Federated Identity Mode')}
actionClose={<AlertActionCloseButton onClose={() => setShowSTSWarn(false)} />}
className="pf-u-mb-lg"
>
<p>
{t(
'olm~This cluster is using Azure Workload Identity / Federated Identity to reach the cloud API. In order for this operator to take the actions it requires directly with the cloud API, provide the Client ID, Tenant ID, and Subscription ID during installation. Manual subscriptions are highly recommended as steps should be taken before upgrade to ensure that the permissions required by the next version are properly accounted for in the role. See the operator description for more details.',
)}
</p>
</Alert>
)}
<div className="row">
<div className="col-xs-6">
<>
Expand All @@ -779,6 +824,70 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
</fieldset>
</div>
)}
{tokenizedAuth === 'Azure' && (
<div className="form-group">
<fieldset>
<label className="co-required">{t('olm~Azure Client ID')}</label>
<FieldLevelHelp>
{t(
'olm~The Azure Client ID required for the operator to access the cloud API.',
)}
</FieldLevelHelp>
<div className="co-toolbar__item">
<TextInput
autoFocus
placeholder={'Azure Client ID'}
aria-label={'Azure Client ID'}
type="text"
value={azureClientId}
onChange={(value) => {
setAzureClientId(value);
}}
/>
</div>
</fieldset>
<fieldset>
<label className="co-required">{t('olm~Azure Tenant ID')}</label>
<FieldLevelHelp>
{t(
'olm~The Azure Tenant ID required for the operator to access the cloud API.',
)}
</FieldLevelHelp>
<div className="co-toolbar__item">
<TextInput
autoFocus
placeholder={'Azure Tenant ID'}
aria-label={'Azure Tenant ID'}
type="text"
value={azureTenantId}
onChange={(value) => {
setAzureTenantId(value);
}}
/>
</div>
</fieldset>
<fieldset>
<label className="co-required">{t('olm~Azure Subscription ID')}</label>
<FieldLevelHelp>
{t(
'olm~The Azure Subscription ID required for the operator to access the cloud API.',
)}
</FieldLevelHelp>
<div className="co-toolbar__item">
<TextInput
autoFocus
placeholder={'Azure Subcription ID'}
aria-label={'Azure Subscription ID'}
type="text"
value={azureSubscriptionId}
onChange={(value) => {
setAzureSubscriptionId(value);
}}
/>
</div>
</fieldset>
</div>
)}
<div className="form-group">
<fieldset>
<label className="co-required">{t('olm~Update channel')}</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ export const getCatalogSourceDisplayName = (packageManifest: PackageManifestKind
);
};

export const shortLivedTokenAuth = 'Short-lived token authentication';

export const isAWSSTSCluster = (
cloudcreds: CloudCredentialKind,
infra: InfrastructureKind,
Expand All @@ -33,3 +31,15 @@ export const isAWSSTSCluster = (
auth?.spec?.serviceAccountIssuer !== ''
);
};

export const isAzureWIFCluster = (
cloudcreds: CloudCredentialKind,
infra: InfrastructureKind,
auth: AuthenticationKind,
) => {
return (
cloudcreds?.spec?.credentialsMode === 'Manual' &&
infra?.status?.platform === 'Azure' &&
auth?.spec?.serviceAccountIssuer !== ''
);
};

0 comments on commit c5c6009

Please sign in to comment.