Skip to content

Commit

Permalink
Add support for Azure Workload Identity / Federated Identity based in…
Browse files Browse the repository at this point in the history
…stalls in OperatorHub
  • Loading branch information
gallettilance committed Nov 30, 2023
1 parent fdcd773 commit 54af6c4
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 19 deletions.
10 changes: 10 additions & 0 deletions frontend/packages/operator-lifecycle-manager/locales/en/olm.json
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,16 @@
"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.",
"Cluster in Workload Identity / Federated Identity Mode": "Cluster in 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. 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
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 { shortLivedTokenAuth, isAWSSTSCluster, isAzureWIFCluster } from './operator-hub-utils';
import { InfraFeatures, OperatorHubItem } from './index';

// t('olm~Basic Install'),
Expand Down Expand Up @@ -379,6 +379,23 @@ export const OperatorHubItemDetails: React.FC<OperatorHubItemDetailsProps> = ({
</p>
</Alert>
)}
{isAzureWIFCluster(cloudCredentials, infrastructure, authentication) &&
showWarn &&
infraFeatures?.find((i) => i === InfraFeatures[shortLivedTokenAuth]) && (
<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
Expand Up @@ -29,7 +29,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, shortLivedTokenAuth } from './operator-hub-utils';
import {
OperatorHubItem,
InstalledState,
Expand Down Expand Up @@ -426,6 +426,17 @@ export const OperatorHubTileView: React.FC<OperatorHubTileViewProps> = (props) =
) {
setTokenizedAuth('AWS');
}
if (
currentItem &&
isAzureWIFCluster(
currentItem.cloudCredentials,
currentItem.infrastructure,
currentItem.authentication,
) &&
currentItem.infraFeatures?.find((i) => i === InfraFeatures[shortLivedTokenAuth])
) {
setTokenizedAuth('Azure');
}
}, [filteredItems]);

const showCommunityOperator = (item: OperatorHubItem) => (ignoreWarning = false) => {
Expand Down
Expand Up @@ -46,9 +46,10 @@ import {
import { subscriptionFor } from '../operator-group';
import { OperatorHubTileView } from './operator-hub-items';
import {
getCatalogSourceDisplayName,
shortLivedTokenAuth,
getCatalogSourceDisplayName,
isAWSSTSCluster,
isAzureWIFCluster,
} from './operator-hub-utils';
import {
OperatorHubItem,
Expand Down Expand Up @@ -168,8 +169,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 Down Expand Up @@ -207,12 +208,15 @@ export const OperatorHubList: React.FC<OperatorHubListProps> = ({
}
});

const infraFeatures = _.uniq(_.compact(infrastructureFeatures));

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

const infraFeatures = _.uniq(_.compact(infrastructureFeatures));

const clusterServiceVersion =
loaded &&
clusterServiceVersionFor(
Expand Down
Expand Up @@ -85,6 +85,9 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
packageManifest?.status ?? {};

const [roleARNText, setRoleARNText] = React.useState(null);
const [azureTenantId, setAzureTenantId] = React.useState(null);
const [azureClientId, setAzureClientId] = React.useState(null);
const [azureSubscriptionId, setAzureSubscriptionId] = React.useState(null);
const { catalogNamespace, channel, pkg, tokenizedAuth, version } = getURLSearchParams();
const [targetNamespace, setTargetNamespace] = React.useState(null);
const [installMode, setInstallMode] = React.useState(null);
Expand Down Expand Up @@ -255,7 +258,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 @@ -418,15 +422,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 @@ -476,7 +502,9 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
!namespaceSupports(selectedTargetNamespace)(selectedInstallMode) ||
(selectedTargetNamespace && cannotResolve) ||
!_.isEmpty(conflictingProvidedAPIs(selectedTargetNamespace)) ||
(tokenizedAuth === 'AWS' && _.isNull(roleARNText));
(tokenizedAuth === 'AWS' && _.isNull(roleARNText)) ||
(tokenizedAuth === 'Azure' &&
[azureClientId, azureTenantId, azureSubscriptionId].some((v) => _.isNil(v) || _.isEmpty(v)));

const formError = () => {
return (
Expand Down Expand Up @@ -755,6 +783,21 @@ export const OperatorHubSubscribeForm: React.FC<OperatorHubSubscribeFormProps> =
</p>
</Alert>
)}
{tokenizedAuth === 'Azure' && showSTSWarn && (
<Alert
isInline
variant="warning"
title={t('olm~Cluster in 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 @@ -780,6 +823,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
Expand Up @@ -33,3 +33,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 54af6c4

Please sign in to comment.