diff --git a/public/assets/account-seeds.json b/public/assets/account-seeds.json
new file mode 100644
index 000000000..5abc6d5c5
--- /dev/null
+++ b/public/assets/account-seeds.json
@@ -0,0 +1,230 @@
+[
+ {
+ "role": {
+ "roleName": "storage-manager-role",
+ "trustPolicy": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": { "Federated": "keycloak.zenko.local" },
+ "Action": "sts:AssumeRoleWithWebIdentity",
+ "Condition": {
+ "StringEquals": {
+ "keycloak:roles": "StorageManager"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "permissionPolicy": {
+ "policyName": "storage-manager-policy",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "FullAccess",
+ "Effect": "Allow",
+ "Action": ["*"],
+ "Resource": "*"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "role": {
+ "roleName": "storage-account-owner-role",
+ "trustPolicy": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": { "Federated": "keycloak.zenko.local" },
+ "Action": "sts:AssumeRoleWithWebIdentity",
+ "Condition": {
+ "StringEquals": { "keycloak:groups": "StorageAccountOwner" }
+ }
+ }
+ ]
+ }
+ },
+ "permissionPolicy": {
+ "policyName": "storage-account-owner-policy",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "FullAccess",
+ "Effect": "Allow",
+ "Action": ["s3:*", "iam:*"],
+ "Resource": ["*"]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "role": {
+ "roleName": "data-consumer-role",
+ "trustPolicy": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Principal": { "Federated": "keycloak.zenko.local" },
+ "Action": "sts:AssumeRoleWithWebIdentity",
+ "Condition": {
+ "StringEquals": { "keycloak:groups": "DataConsumer" }
+ }
+ }
+ ]
+ }
+ },
+ "permissionPolicy": {
+ "policyName": "data-consumer-policy",
+ "policyDocument": {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": "s3:ListAllMyBuckets",
+ "Resource": "*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": ["s3:ListBucket", "s3:GetBucketLocation"],
+ "Resource": "*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:MetadataSearch",
+ "s3:PutObject",
+ "s3:PutObjectAcl",
+ "s3:GetObject",
+ "s3:GetObjectAcl",
+ "s3:DeleteObject",
+ "s3:RestoreObject",
+ "s3:GetBucketVersioning",
+ "s3:GetBucketCors",
+ "s3:GetBucketAcl",
+ "s3:GetBucketObjectLockConfiguration",
+ "s3:ListObjectsV2",
+ "s3:ListObjectVersions",
+ "s3:PutObjectLockConfiguration",
+ "s3:DeleteObjects",
+ "s3:GetObjectRetention",
+ "s3:GetObjectLegalHold",
+ "s3:PutObjectRetention",
+ "s3:PutObjectLegalHold",
+ "s3:HeadObject",
+ "s3:CopyObject",
+ "s3:GetObjectTagging",
+ "s3:PutObjectTagging",
+ "s3:GetReplicationConfiguration",
+ "s3:GetLifecycleConfiguration",
+ "s3:DeleteObjectVersion",
+ "s3:PutLifecycleConfiguration",
+ "s3:PutReplicationConfiguration",
+ "s3:ListObjectVersion",
+ "s3:GetObjectVersion",
+ "s3:GetObjectVersionRetention",
+ "s3:GetObjectVersionLegalHold",
+ "s3:PutObjectVersionRetention",
+ "s3:PutObjectVersionLegalHold",
+ "s3:GetObjectVersionTagging",
+ "s3:DeleteObjectVersionTagging",
+ "s3:PutObjectVersionTagging",
+ "s3:GetObjectVersionAcl",
+ "s3:PutObjectVersionAcl",
+ "s3:GetBucketTagging",
+ "s3:PutBucketTagging",
+ "s3:DeleteBucketTagging"
+ ],
+ "Resource": "*"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "permissionPolicy": {
+ "policyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetLifecycleConfiguration",
+ "s3:GetBucketVersioning",
+ "s3:ListBucket",
+ "s3:ListBucketVersions",
+ "s3:ListBucketMultipartUploads",
+ "s3:GetObjectTagging",
+ "s3:GetObjectVersionTagging",
+ "s3:GetObject",
+ "s3:GetObjectVersion"
+ ],
+ "Effect": "Allow",
+ "Resource": ["*"],
+ "Sid": "LifecycleExpirationBucketProcessor"
+ }
+ ],
+ "Version": "2012-10-17"
+ },
+ "policyName": "backbeat-lifecycle-bp-1"
+ },
+ "role": {
+ "roleName": "backbeat-lifecycle-bp-1",
+ "trustPolicy": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::000000000000:user/scality-internal/backbeat-lifecycle-bp-1"
+ }
+ }
+ ],
+ "Version": "2012-10-17"
+ }
+ }
+ },
+ {
+ "permissionPolicy": {
+ "policyDocument": {
+ "Statement": [
+ {
+ "Action": [
+ "s3:GetObject",
+ "s3:GetObjectVersion",
+ "s3:DeleteObject",
+ "s3:DeleteObjectVersion",
+ "s3:AbortMultipartUpload"
+ ],
+ "Effect": "Allow",
+ "Resource": ["*"],
+ "Sid": "LifecycleExpirationObjectProcessor"
+ }
+ ],
+ "Version": "2012-10-17"
+ },
+ "policyName": "backbeat-lifecycle-op-1"
+ },
+ "role": {
+ "roleName": "backbeat-lifecycle-op-1",
+ "trustPolicy": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "AWS": "arn:aws:iam::000000000000:user/scality-internal/backbeat-lifecycle-op-1"
+ }
+ }
+ ],
+ "Version": "2012-10-17"
+ }
+ }
+ }
+]
diff --git a/src/js/vault.ts b/src/js/vault.ts
new file mode 100644
index 000000000..399268061
--- /dev/null
+++ b/src/js/vault.ts
@@ -0,0 +1,11 @@
+// TODO: AccountSeeds should be returned by Vault API
+export function getAccountSeeds() {
+ return fetch('/account-seeds.json', {
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
+ }).then((res) => {
+ if (!res.ok) {
+ throw Error('Can not fetch Account Seeds!!');
+ }
+ return res.json();
+ });
+}
diff --git a/src/react/account/iamAttachment/AttachmentTable.tsx b/src/react/account/iamAttachment/AttachmentTable.tsx
index b0fdace4e..79089a2c7 100644
--- a/src/react/account/iamAttachment/AttachmentTable.tsx
+++ b/src/react/account/iamAttachment/AttachmentTable.tsx
@@ -524,6 +524,7 @@ export const AttachmentTable = <
icon={}
label="Remove"
variant="danger"
+ disabled={!!entity.disableDetach}
/>
),
},
diff --git a/src/react/account/iamAttachment/AttachmentTabs.tsx b/src/react/account/iamAttachment/AttachmentTabs.tsx
index 236d7a734..108a7c352 100644
--- a/src/react/account/iamAttachment/AttachmentTabs.tsx
+++ b/src/react/account/iamAttachment/AttachmentTabs.tsx
@@ -2,8 +2,10 @@ import { Loader } from '@scality/core-ui';
import { useReducer } from 'react';
import { useLocation, useParams } from 'react-router';
import { useTheme } from 'styled-components';
+import { useQuery } from 'react-query';
import { useIAMClient } from '../../IAMProvider';
import {
+ getAccountSeedsQuery,
getListAttachedUserPoliciesQuery,
getListEntitiesForPolicyQuery,
getListGroupsQuery,
@@ -95,10 +97,12 @@ const AttachmentTableProxy = <
const AttachmentTabs = ({
resourceType,
resourceId,
+ resourceName,
onAttachmentsOperationsChanged,
}: {
resourceType: ResourceType;
resourceId: string;
+ resourceName: string;
onAttachmentsOperationsChanged: (
attachmentOperations: AttachmentOperation[],
) => void;
@@ -133,6 +137,12 @@ const AttachmentTabs = ({
tabLineColor: backgroundLevel4,
};
+ const { data: accountSeeds } = useQuery(getAccountSeedsQuery());
+ const policyRolePair =
+ accountSeeds?.filter(
+ (seed) => seed.permissionPolicy.policyName === resourceName,
+ ) || [];
+
return (
{resourceType === 'policy' && (
@@ -289,10 +299,15 @@ const AttachmentTabs = ({
getAttachedEntitesFromResult={(response) => {
return (
response.PolicyRoles?.map((role) => {
+ const disableDetach =
+ !!policyRolePair.find(
+ (pair) => pair.role.roleName === role.RoleName,
+ ) !== undefined;
return {
name: role.RoleName || '',
id: role.RoleName || '',
type: 'role',
+ disableDetach,
};
}) || []
);
diff --git a/src/react/account/iamAttachment/AttachmentTypes.ts b/src/react/account/iamAttachment/AttachmentTypes.ts
index 34a7dc693..153b82d81 100644
--- a/src/react/account/iamAttachment/AttachmentTypes.ts
+++ b/src/react/account/iamAttachment/AttachmentTypes.ts
@@ -5,6 +5,7 @@ export type AttachableEntity = {
name: string;
id: string;
type: EntityType;
+ disableDetach?: boolean;
};
export enum AttachmentAction {
diff --git a/src/react/account/iamAttachment/Attachments.tsx b/src/react/account/iamAttachment/Attachments.tsx
index 70d19f46b..2ad6ff0dd 100644
--- a/src/react/account/iamAttachment/Attachments.tsx
+++ b/src/react/account/iamAttachment/Attachments.tsx
@@ -1,5 +1,4 @@
import { BasicText, EmphaseText, LargerText } from '@scality/core-ui';
-import { Button } from '@scality/core-ui/dist/next';
import { useState } from 'react';
import { useParams, useRouteMatch } from 'react-router';
import styled from 'styled-components';
@@ -75,6 +74,7 @@ const Attachments = () => {
@@ -84,7 +84,11 @@ const Attachments = () => {
resourceId={resourceId}
resourceName={resourceName}
resourceType={resourceType}
- redirectUrl={isAttachToPolicy ? `/accounts/${account?.Name}/policies` : `/accounts/${account?.Name}/users`}
+ redirectUrl={
+ isAttachToPolicy
+ ? `/accounts/${account?.Name}/policies`
+ : `/accounts/${account?.Name}/users`
+ }
/>
>
diff --git a/src/react/queries.ts b/src/react/queries.ts
index c4107bb85..8a16fab64 100644
--- a/src/react/queries.ts
+++ b/src/react/queries.ts
@@ -4,6 +4,7 @@ import { APIWorkflows, Workflows, Workflow } from '../types/workflow';
import { generateExpirationName, generateStreamName } from './workflow/utils';
import IAMClient from '../js/IAMClient';
import { QueryFunctionContext } from 'react-query';
+import { getAccountSeeds } from '../js/vault';
// Copy paste form legacy redux workflow
export const makeWorkflows = (apiWorkflows: APIWorkflows): Workflows => {
@@ -161,3 +162,8 @@ export const getListAttachedUserPoliciesQuery = (
refetchOnMount: false,
refetchOnWindowFocus: false,
});
+
+export const getAccountSeedsQuery = () => ({
+ queryKey: ['AccountSeeds'],
+ queryFn: getAccountSeeds,
+});