Skip to content

Commit 477a4e9

Browse files
Merge pull request #998 from ecordell/update-perms
Bug 1741475: test(e2e): Update permissions during operator upgrade
2 parents 33c4d96 + 51b3345 commit 477a4e9

File tree

2 files changed

+398
-16
lines changed

2 files changed

+398
-16
lines changed

test/e2e/installplan_e2e_test.go

Lines changed: 377 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/blang/semver"
1111
"github.com/stretchr/testify/require"
1212
appsv1 "k8s.io/api/apps/v1"
13+
authorizationv1 "k8s.io/api/authorization/v1"
1314
corev1 "k8s.io/api/core/v1"
1415
rbacv1 "k8s.io/api/rbac/v1"
1516
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
@@ -996,7 +997,7 @@ func TestInstallPlanWithCRDSchemaChange(t *testing.T) {
996997
}
997998
}
998999

999-
func TestUpdateInstallPlan(t *testing.T) {
1000+
func TestUpdateCatalogForSubscription(t *testing.T) {
10001001
defer cleaner.NotifyTestComplete(t, true)
10011002

10021003
// crdVersionKey uniquely identifies a version within a CRD.
@@ -1006,6 +1007,381 @@ func TestUpdateInstallPlan(t *testing.T) {
10061007
storage bool
10071008
}
10081009

1010+
t.Run("AmplifyPermissions", func(t *testing.T) {
1011+
defer cleaner.NotifyTestComplete(t, true)
1012+
1013+
c := newKubeClient(t)
1014+
crc := newCRClient(t)
1015+
defer func() {
1016+
require.NoError(t, crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{}))
1017+
}()
1018+
1019+
// Build initial catalog
1020+
mainPackageName := genName("nginx-amplify-")
1021+
mainPackageStable := fmt.Sprintf("%s-stable", mainPackageName)
1022+
stableChannel := "stable"
1023+
crdPlural := genName("ins-amplify-")
1024+
crdName := crdPlural + ".cluster.com"
1025+
mainCRD := apiextensions.CustomResourceDefinition{
1026+
ObjectMeta: metav1.ObjectMeta{
1027+
Name: crdName,
1028+
},
1029+
Spec: apiextensions.CustomResourceDefinitionSpec{
1030+
Group: "cluster.com",
1031+
Versions: []apiextensions.CustomResourceDefinitionVersion{
1032+
{
1033+
Name: "v1alpha1",
1034+
Served: true,
1035+
Storage: true,
1036+
},
1037+
},
1038+
Names: apiextensions.CustomResourceDefinitionNames{
1039+
Plural: crdPlural,
1040+
Singular: crdPlural,
1041+
Kind: crdPlural,
1042+
ListKind: "list" + crdPlural,
1043+
},
1044+
Scope: "Namespaced",
1045+
},
1046+
}
1047+
1048+
// Generate permissions
1049+
serviceAccountName := genName("nginx-sa")
1050+
permissions := []install.StrategyDeploymentPermissions{
1051+
{
1052+
ServiceAccountName: serviceAccountName,
1053+
Rules: []rbacv1.PolicyRule{
1054+
{
1055+
Verbs: []string{rbac.VerbAll},
1056+
APIGroups: []string{"cluster.com"},
1057+
Resources: []string{crdPlural},
1058+
},
1059+
},
1060+
},
1061+
}
1062+
// Generate permissions
1063+
clusterPermissions := []install.StrategyDeploymentPermissions{
1064+
{
1065+
ServiceAccountName: serviceAccountName,
1066+
Rules: []rbacv1.PolicyRule{
1067+
{
1068+
Verbs: []string{rbac.VerbAll},
1069+
APIGroups: []string{"cluster.com"},
1070+
Resources: []string{crdPlural},
1071+
},
1072+
},
1073+
},
1074+
}
1075+
1076+
// Create the catalog sources
1077+
mainNamedStrategy := newNginxInstallStrategy(genName("dep-"), permissions, clusterPermissions)
1078+
mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, nil, mainNamedStrategy)
1079+
mainCatalogName := genName("mock-ocs-amplify-")
1080+
mainManifests := []registry.PackageManifest{
1081+
{
1082+
PackageName: mainPackageName,
1083+
Channels: []registry.PackageChannel{
1084+
{Name: stableChannel, CurrentCSVName: mainCSV.GetName()},
1085+
},
1086+
DefaultChannelName: stableChannel,
1087+
},
1088+
}
1089+
_, cleanupMainCatalogSource := createInternalCatalogSource(t, c, crc, mainCatalogName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []v1alpha1.ClusterServiceVersion{mainCSV})
1090+
defer cleanupMainCatalogSource()
1091+
// Attempt to get the catalog source before creating install plan
1092+
_, err := fetchCatalogSource(t, crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced)
1093+
require.NoError(t, err)
1094+
1095+
subscriptionName := genName("sub-nginx-update-perms1")
1096+
subscriptionCleanup := createSubscriptionForCatalog(t, crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", v1alpha1.ApprovalAutomatic)
1097+
defer subscriptionCleanup()
1098+
1099+
subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker)
1100+
require.NoError(t, err)
1101+
require.NotNil(t, subscription)
1102+
require.NotNil(t, subscription.Status.InstallPlanRef)
1103+
require.Equal(t, mainCSV.GetName(), subscription.Status.CurrentCSV)
1104+
1105+
installPlanName := subscription.Status.InstallPlanRef.Name
1106+
1107+
// Wait for InstallPlan to be status: Complete before checking resource presence
1108+
fetchedInstallPlan, err := fetchInstallPlan(t, crc, installPlanName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete))
1109+
require.NoError(t, err)
1110+
1111+
require.Equal(t, v1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase)
1112+
1113+
// Verify CSV is created
1114+
_, err = awaitCSV(t, crc, testNamespace, mainCSV.GetName(), csvSucceededChecker)
1115+
require.NoError(t, err)
1116+
1117+
// Update CatalogSource with a new CSV with more permissions
1118+
updatedPermissions := []install.StrategyDeploymentPermissions{
1119+
{
1120+
ServiceAccountName: serviceAccountName,
1121+
Rules: []rbacv1.PolicyRule{
1122+
{
1123+
Verbs: []string{rbac.VerbAll},
1124+
APIGroups: []string{"cluster.com"},
1125+
Resources: []string{crdPlural},
1126+
},
1127+
{
1128+
Verbs: []string{rbac.VerbAll},
1129+
APIGroups: []string{"local.cluster.com"},
1130+
Resources: []string{"locals"},
1131+
},
1132+
},
1133+
},
1134+
}
1135+
updatedClusterPermissions := []install.StrategyDeploymentPermissions{
1136+
{
1137+
ServiceAccountName: serviceAccountName,
1138+
Rules: []rbacv1.PolicyRule{
1139+
{
1140+
Verbs: []string{rbac.VerbAll},
1141+
APIGroups: []string{"cluster.com"},
1142+
Resources: []string{crdPlural},
1143+
},
1144+
{
1145+
Verbs: []string{rbac.VerbAll},
1146+
APIGroups: []string{"two.cluster.com"},
1147+
Resources: []string{"twos"},
1148+
},
1149+
},
1150+
},
1151+
}
1152+
1153+
// Create the catalog sources
1154+
updatedNamedStrategy := newNginxInstallStrategy(genName("dep-"), updatedPermissions, updatedClusterPermissions)
1155+
updatedCSV := newCSV(mainPackageStable+"-next", testNamespace, mainCSV.GetName(), semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, updatedNamedStrategy)
1156+
updatedManifests := []registry.PackageManifest{
1157+
{
1158+
PackageName: mainPackageName,
1159+
Channels: []registry.PackageChannel{
1160+
{Name: stableChannel, CurrentCSVName: updatedCSV.GetName()},
1161+
},
1162+
DefaultChannelName: stableChannel,
1163+
},
1164+
}
1165+
// Update catalog with updated CSV with more permissions
1166+
updateInternalCatalog(t, c, crc, mainCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{mainCRD}, []v1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests)
1167+
1168+
_, err = fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName()))
1169+
require.NoError(t, err)
1170+
1171+
updatedInstallPlanName := subscription.Status.InstallPlanRef.Name
1172+
1173+
// Wait for InstallPlan to be status: Complete before checking resource presence
1174+
fetchedUpdatedInstallPlan, err := fetchInstallPlan(t, crc, updatedInstallPlanName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete))
1175+
require.NoError(t, err)
1176+
require.Equal(t, v1alpha1.InstallPlanPhaseComplete, fetchedUpdatedInstallPlan.Status.Phase)
1177+
1178+
// Wait for csv to update
1179+
_, err = awaitCSV(t, crc, testNamespace, updatedCSV.GetName(), csvSucceededChecker)
1180+
require.NoError(t, err)
1181+
1182+
// If the CSV is succeeded, we successfully rolled out the RBAC changes
1183+
})
1184+
1185+
t.Run("AttenuatePermissions", func(t *testing.T) {
1186+
defer cleaner.NotifyTestComplete(t, true)
1187+
1188+
c := newKubeClient(t)
1189+
crc := newCRClient(t)
1190+
defer func() {
1191+
require.NoError(t, crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{}))
1192+
}()
1193+
1194+
// Build initial catalog
1195+
mainPackageName := genName("nginx-attenuate-")
1196+
mainPackageStable := fmt.Sprintf("%s-stable", mainPackageName)
1197+
stableChannel := "stable"
1198+
crdPlural := genName("ins-attenuate-")
1199+
crdName := crdPlural + ".cluster.com"
1200+
mainCRD := apiextensions.CustomResourceDefinition{
1201+
ObjectMeta: metav1.ObjectMeta{
1202+
Name: crdName,
1203+
},
1204+
Spec: apiextensions.CustomResourceDefinitionSpec{
1205+
Group: "cluster.com",
1206+
Versions: []apiextensions.CustomResourceDefinitionVersion{
1207+
{
1208+
Name: "v1alpha1",
1209+
Served: true,
1210+
Storage: true,
1211+
},
1212+
},
1213+
Names: apiextensions.CustomResourceDefinitionNames{
1214+
Plural: crdPlural,
1215+
Singular: crdPlural,
1216+
Kind: crdPlural,
1217+
ListKind: "list" + crdPlural,
1218+
},
1219+
Scope: "Namespaced",
1220+
},
1221+
}
1222+
1223+
// Generate permissions
1224+
serviceAccountName := genName("nginx-sa")
1225+
permissions := []install.StrategyDeploymentPermissions{
1226+
{
1227+
ServiceAccountName: serviceAccountName,
1228+
Rules: []rbacv1.PolicyRule{
1229+
{
1230+
Verbs: []string{rbac.VerbAll},
1231+
APIGroups: []string{"cluster.com"},
1232+
Resources: []string{crdPlural},
1233+
},
1234+
{
1235+
Verbs: []string{rbac.VerbAll},
1236+
APIGroups: []string{"local.cluster.com"},
1237+
Resources: []string{"locals"},
1238+
},
1239+
},
1240+
},
1241+
}
1242+
// Generate permissions
1243+
clusterPermissions := []install.StrategyDeploymentPermissions{
1244+
{
1245+
ServiceAccountName: serviceAccountName,
1246+
Rules: []rbacv1.PolicyRule{
1247+
{
1248+
Verbs: []string{rbac.VerbAll},
1249+
APIGroups: []string{"cluster.com"},
1250+
Resources: []string{crdPlural},
1251+
},
1252+
{
1253+
Verbs: []string{rbac.VerbAll},
1254+
APIGroups: []string{"two.cluster.com"},
1255+
Resources: []string{"twos"},
1256+
},
1257+
},
1258+
},
1259+
}
1260+
1261+
// Create the catalog sources
1262+
mainNamedStrategy := newNginxInstallStrategy(genName("dep-"), permissions, clusterPermissions)
1263+
mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, nil, mainNamedStrategy)
1264+
mainCatalogName := genName("mock-ocs-main-update-perms1-")
1265+
mainManifests := []registry.PackageManifest{
1266+
{
1267+
PackageName: mainPackageName,
1268+
Channels: []registry.PackageChannel{
1269+
{Name: stableChannel, CurrentCSVName: mainCSV.GetName()},
1270+
},
1271+
DefaultChannelName: stableChannel,
1272+
},
1273+
}
1274+
_, cleanupMainCatalogSource := createInternalCatalogSource(t, c, crc, mainCatalogName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []v1alpha1.ClusterServiceVersion{mainCSV})
1275+
defer cleanupMainCatalogSource()
1276+
// Attempt to get the catalog source before creating install plan
1277+
_, err := fetchCatalogSource(t, crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced)
1278+
require.NoError(t, err)
1279+
1280+
subscriptionName := genName("sub-nginx-update-perms1")
1281+
subscriptionCleanup := createSubscriptionForCatalog(t, crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", v1alpha1.ApprovalAutomatic)
1282+
defer subscriptionCleanup()
1283+
1284+
subscription, err := fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker)
1285+
require.NoError(t, err)
1286+
require.NotNil(t, subscription)
1287+
require.NotNil(t, subscription.Status.InstallPlanRef)
1288+
require.Equal(t, mainCSV.GetName(), subscription.Status.CurrentCSV)
1289+
1290+
installPlanName := subscription.Status.InstallPlanRef.Name
1291+
1292+
// Wait for InstallPlan to be status: Complete before checking resource presence
1293+
fetchedInstallPlan, err := fetchInstallPlan(t, crc, installPlanName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete))
1294+
require.NoError(t, err)
1295+
1296+
require.Equal(t, v1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase)
1297+
1298+
// Verify CSV is created
1299+
_, err = awaitCSV(t, crc, testNamespace, mainCSV.GetName(), csvSucceededChecker)
1300+
require.NoError(t, err)
1301+
1302+
// Update CatalogSource with a new CSV with more permissions
1303+
updatedPermissions := []install.StrategyDeploymentPermissions{
1304+
{
1305+
ServiceAccountName: serviceAccountName,
1306+
Rules: []rbacv1.PolicyRule{
1307+
{
1308+
Verbs: []string{rbac.VerbAll},
1309+
APIGroups: []string{"local.cluster.com"},
1310+
Resources: []string{"locals"},
1311+
},
1312+
},
1313+
},
1314+
}
1315+
updatedClusterPermissions := []install.StrategyDeploymentPermissions{
1316+
{
1317+
ServiceAccountName: serviceAccountName,
1318+
Rules: []rbacv1.PolicyRule{
1319+
{
1320+
Verbs: []string{rbac.VerbAll},
1321+
APIGroups: []string{"two.cluster.com"},
1322+
Resources: []string{"twos"},
1323+
},
1324+
},
1325+
},
1326+
}
1327+
1328+
// Create the catalog sources
1329+
updatedNamedStrategy := newNginxInstallStrategy(genName("dep-"), updatedPermissions, updatedClusterPermissions)
1330+
updatedCSV := newCSV(mainPackageStable+"-next", testNamespace, mainCSV.GetName(), semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, updatedNamedStrategy)
1331+
updatedManifests := []registry.PackageManifest{
1332+
{
1333+
PackageName: mainPackageName,
1334+
Channels: []registry.PackageChannel{
1335+
{Name: stableChannel, CurrentCSVName: updatedCSV.GetName()},
1336+
},
1337+
DefaultChannelName: stableChannel,
1338+
},
1339+
}
1340+
// Update catalog with updated CSV with more permissions
1341+
updateInternalCatalog(t, c, crc, mainCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{mainCRD}, []v1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests)
1342+
1343+
// Wait for subscription to update its status
1344+
_, err = fetchSubscription(t, crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName()))
1345+
require.NoError(t, err)
1346+
1347+
updatedInstallPlanName := subscription.Status.InstallPlanRef.Name
1348+
1349+
// Wait for InstallPlan to be status: Complete before checking resource presence
1350+
fetchedUpdatedInstallPlan, err := fetchInstallPlan(t, crc, updatedInstallPlanName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete))
1351+
require.NoError(t, err)
1352+
require.Equal(t, v1alpha1.InstallPlanPhaseComplete, fetchedUpdatedInstallPlan.Status.Phase)
1353+
1354+
// Wait for csv to update
1355+
_, err = awaitCSV(t, crc, testNamespace, updatedCSV.GetName(), csvSucceededChecker)
1356+
require.NoError(t, err)
1357+
1358+
// Wait for ServiceAccount to not have access anymore
1359+
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
1360+
res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(&authorizationv1.SubjectAccessReview{
1361+
Spec: authorizationv1.SubjectAccessReviewSpec{
1362+
User: "system:serviceaccount:" + testNamespace + ":" + serviceAccountName,
1363+
ResourceAttributes: &authorizationv1.ResourceAttributes{
1364+
Group: "cluster.com",
1365+
Version: "v1alpha1",
1366+
Resource: crdPlural,
1367+
Verb: rbac.VerbAll,
1368+
},
1369+
},
1370+
})
1371+
if err != nil {
1372+
return false, err
1373+
}
1374+
if res == nil {
1375+
return false, nil
1376+
}
1377+
t.Log("checking serviceaccount for permission")
1378+
1379+
// should not be allowed
1380+
return !res.Status.Allowed, nil
1381+
})
1382+
1383+
})
1384+
10091385
t.Run("UpdateSingleExistingCRDOwner", func(t *testing.T) {
10101386
defer cleaner.NotifyTestComplete(t, true)
10111387

0 commit comments

Comments
 (0)