feat(rbac) remove list ingresses permissions EE-1304 (#5458)
* feat(RBAC) EE-1304 list ingresses of current namespace other than all namespaces at front end side * feat(RBAC) EE-1304 remove list ingresses from clusterrole Co-authored-by: Simon Meng <simon.meng@portainer.io>pull/5560/head
parent
35013e7b6a
commit
7760595f21
|
@ -18,15 +18,10 @@ func getPortainerUserDefaultPolicies() []rbacv1.PolicyRule {
|
||||||
Resources: []string{"storageclasses"},
|
Resources: []string{"storageclasses"},
|
||||||
APIGroups: []string{"storage.k8s.io"},
|
APIGroups: []string{"storage.k8s.io"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Verbs: []string{"list"},
|
|
||||||
Resources: []string{"ingresses"},
|
|
||||||
APIGroups: []string{"networking.k8s.io"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kcl *KubeClient) createPortainerUserClusterRole() error {
|
func (kcl *KubeClient) upsertPortainerK8sClusterRoles() error {
|
||||||
clusterRole := &rbacv1.ClusterRole{
|
clusterRole := &rbacv1.ClusterRole{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: portainerUserCRName,
|
Name: portainerUserCRName,
|
||||||
|
@ -35,9 +30,14 @@ func (kcl *KubeClient) createPortainerUserClusterRole() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := kcl.cli.RbacV1().ClusterRoles().Create(clusterRole)
|
_, err := kcl.cli.RbacV1().ClusterRoles().Create(clusterRole)
|
||||||
if err != nil && !k8serrors.IsAlreadyExists(err) {
|
if err != nil {
|
||||||
|
if k8serrors.IsAlreadyExists(err) {
|
||||||
|
_, err = kcl.cli.RbacV1().ClusterRoles().Update(clusterRole)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ func (kcl *KubeClient) SetupUserServiceAccount(userID int, teamIDs []int, restri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kcl *KubeClient) ensureRequiredResourcesExist() error {
|
func (kcl *KubeClient) ensureRequiredResourcesExist() error {
|
||||||
return kcl.createPortainerUserClusterRole()
|
return kcl.upsertPortainerK8sClusterRoles()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kcl *KubeClient) createUserServiceAccount(namespace, serviceAccountName string) error {
|
func (kcl *KubeClient) createUserServiceAccount(namespace, serviceAccountName string) error {
|
||||||
|
|
|
@ -1347,7 +1347,7 @@
|
||||||
class="form-control"
|
class="form-control"
|
||||||
name="ingress_class_{{ $index }}"
|
name="ingress_class_{{ $index }}"
|
||||||
ng-model="publishedPort.IngressName"
|
ng-model="publishedPort.IngressName"
|
||||||
ng-options="ingress.Name as ingress.Name for ingress in ctrl.filteredIngresses"
|
ng-options="ingress.Name as ingress.Name for ingress in ctrl.ingresses"
|
||||||
ng-required="!publishedPort.NeedsDeletion"
|
ng-required="!publishedPort.NeedsDeletion"
|
||||||
ng-change="ctrl.onChangePortMappingIngress($index)"
|
ng-change="ctrl.onChangePortMappingIngress($index)"
|
||||||
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
|
ng-disabled="ctrl.disableLoadBalancerEdit() || ctrl.isEditAndNotNewPublishedPort($index)"
|
||||||
|
|
|
@ -371,7 +371,7 @@ class KubernetesCreateApplicationController {
|
||||||
/* #region PUBLISHED PORTS UI MANAGEMENT */
|
/* #region PUBLISHED PORTS UI MANAGEMENT */
|
||||||
addPublishedPort() {
|
addPublishedPort() {
|
||||||
const p = new KubernetesApplicationPublishedPortFormValue();
|
const p = new KubernetesApplicationPublishedPortFormValue();
|
||||||
const ingresses = this.filteredIngresses;
|
const ingresses = this.ingresses;
|
||||||
p.IngressName = ingresses && ingresses.length ? ingresses[0].Name : undefined;
|
p.IngressName = ingresses && ingresses.length ? ingresses[0].Name : undefined;
|
||||||
p.IngressHost = ingresses && ingresses.length ? ingresses[0].Hosts[0] : undefined;
|
p.IngressHost = ingresses && ingresses.length ? ingresses[0].Hosts[0] : undefined;
|
||||||
p.IngressHosts = ingresses && ingresses.length ? ingresses[0].Hosts : undefined;
|
p.IngressHosts = ingresses && ingresses.length ? ingresses[0].Hosts : undefined;
|
||||||
|
@ -382,7 +382,7 @@ class KubernetesCreateApplicationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPublishedPorts() {
|
resetPublishedPorts() {
|
||||||
const ingresses = this.filteredIngresses;
|
const ingresses = this.ingresses;
|
||||||
_.forEach(this.formValues.PublishedPorts, (p) => {
|
_.forEach(this.formValues.PublishedPorts, (p) => {
|
||||||
p.IngressName = ingresses && ingresses.length ? ingresses[0].Name : undefined;
|
p.IngressName = ingresses && ingresses.length ? ingresses[0].Name : undefined;
|
||||||
p.IngressHost = ingresses && ingresses.length ? ingresses[0].Hosts[0] : undefined;
|
p.IngressHost = ingresses && ingresses.length ? ingresses[0].Hosts[0] : undefined;
|
||||||
|
@ -441,7 +441,7 @@ class KubernetesCreateApplicationController {
|
||||||
|
|
||||||
onChangePortMappingIngress(index) {
|
onChangePortMappingIngress(index) {
|
||||||
const publishedPort = this.formValues.PublishedPorts[index];
|
const publishedPort = this.formValues.PublishedPorts[index];
|
||||||
const ingress = _.find(this.filteredIngresses, { Name: publishedPort.IngressName });
|
const ingress = _.find(this.ingresses, { Name: publishedPort.IngressName });
|
||||||
publishedPort.IngressHosts = ingress.Hosts;
|
publishedPort.IngressHosts = ingress.Hosts;
|
||||||
this.ingressHostnames = ingress.Hosts;
|
this.ingressHostnames = ingress.Hosts;
|
||||||
publishedPort.IngressHost = this.ingressHostnames.length ? this.ingressHostnames[0] : [];
|
publishedPort.IngressHost = this.ingressHostnames.length ? this.ingressHostnames[0] : [];
|
||||||
|
@ -650,7 +650,7 @@ class KubernetesCreateApplicationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
publishViaIngressEnabled() {
|
publishViaIngressEnabled() {
|
||||||
return this.filteredIngresses.length;
|
return this.ingresses.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
isEditAndNoChangesMade() {
|
isEditAndNoChangesMade() {
|
||||||
|
@ -871,8 +871,10 @@ class KubernetesCreateApplicationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshIngresses(namespace) {
|
refreshIngresses(namespace) {
|
||||||
this.filteredIngresses = _.filter(this.ingresses, { Namespace: namespace });
|
return this.$async(async () => {
|
||||||
this.ingressHostnames = this.filteredIngresses.length ? this.filteredIngresses[0].Hosts : [];
|
try {
|
||||||
|
this.ingresses = await this.KubernetesIngressService.get(namespace);
|
||||||
|
this.ingressHostnames = this.ingresses.length ? this.ingresses[0].Hosts : [];
|
||||||
if (!this.publishViaIngressEnabled()) {
|
if (!this.publishViaIngressEnabled()) {
|
||||||
if (this.savedFormValues) {
|
if (this.savedFormValues) {
|
||||||
this.formValues.PublishingType = this.savedFormValues.PublishingType;
|
this.formValues.PublishingType = this.savedFormValues.PublishingType;
|
||||||
|
@ -880,7 +882,11 @@ class KubernetesCreateApplicationController {
|
||||||
this.formValues.PublishingType = this.ApplicationPublishingTypes.INTERNAL;
|
this.formValues.PublishingType = this.ApplicationPublishingTypes.INTERNAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.formValues.OriginalIngresses = this.filteredIngresses;
|
this.formValues.OriginalIngresses = this.ingresses;
|
||||||
|
} catch (err) {
|
||||||
|
this.Notifications.error('Failure', err, 'Unable to retrieve ingresses');
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshNamespaceData(namespace) {
|
refreshNamespaceData(namespace) {
|
||||||
|
@ -990,13 +996,11 @@ class KubernetesCreateApplicationController {
|
||||||
this.state.useLoadBalancer = this.endpoint.Kubernetes.Configuration.UseLoadBalancer;
|
this.state.useLoadBalancer = this.endpoint.Kubernetes.Configuration.UseLoadBalancer;
|
||||||
this.state.useServerMetrics = this.endpoint.Kubernetes.Configuration.UseServerMetrics;
|
this.state.useServerMetrics = this.endpoint.Kubernetes.Configuration.UseServerMetrics;
|
||||||
|
|
||||||
const [resourcePools, nodes, ingresses, nodesLimits] = await Promise.all([
|
const [resourcePools, nodes, nodesLimits] = await Promise.all([
|
||||||
this.KubernetesResourcePoolService.get(),
|
this.KubernetesResourcePoolService.get(),
|
||||||
this.KubernetesNodeService.get(),
|
this.KubernetesNodeService.get(),
|
||||||
this.KubernetesIngressService.get(),
|
|
||||||
this.KubernetesNodesLimitsService.get(),
|
this.KubernetesNodesLimitsService.get(),
|
||||||
]);
|
]);
|
||||||
this.ingresses = ingresses;
|
|
||||||
this.nodesLimits = nodesLimits;
|
this.nodesLimits = nodesLimits;
|
||||||
|
|
||||||
this.resourcePools = _.filter(resourcePools, (resourcePool) => !KubernetesNamespaceHelper.isSystemNamespace(resourcePool.Namespace.Name));
|
this.resourcePools = _.filter(resourcePools, (resourcePool) => !KubernetesNamespaceHelper.isSystemNamespace(resourcePool.Namespace.Name));
|
||||||
|
@ -1023,9 +1027,9 @@ class KubernetesCreateApplicationController {
|
||||||
this.configurations,
|
this.configurations,
|
||||||
this.persistentVolumeClaims,
|
this.persistentVolumeClaims,
|
||||||
this.nodesLabels,
|
this.nodesLabels,
|
||||||
this.filteredIngresses
|
this.ingresses
|
||||||
);
|
);
|
||||||
this.formValues.OriginalIngresses = this.filteredIngresses;
|
this.formValues.OriginalIngresses = this.ingresses;
|
||||||
this.formValues.ImageModel = await this.parseImageConfiguration(this.formValues.ImageModel);
|
this.formValues.ImageModel = await this.parseImageConfiguration(this.formValues.ImageModel);
|
||||||
this.savedFormValues = angular.copy(this.formValues);
|
this.savedFormValues = angular.copy(this.formValues);
|
||||||
delete this.formValues.ApplicationType;
|
delete this.formValues.ApplicationType;
|
||||||
|
@ -1042,7 +1046,6 @@ class KubernetesCreateApplicationController {
|
||||||
await this.refreshNamespaceData(namespace);
|
await this.refreshNamespaceData(namespace);
|
||||||
} else {
|
} else {
|
||||||
this.formValues.AutoScaler = KubernetesApplicationHelper.generateAutoScalerFormValueFromHorizontalPodAutoScaler(null, this.formValues.ReplicaCount);
|
this.formValues.AutoScaler = KubernetesApplicationHelper.generateAutoScalerFormValueFromHorizontalPodAutoScaler(null, this.formValues.ReplicaCount);
|
||||||
this.formValues.OriginalIngressClasses = angular.copy(this.ingresses);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.isEdit) {
|
if (this.state.isEdit) {
|
||||||
|
|
|
@ -293,7 +293,7 @@ class KubernetesResourcePoolController {
|
||||||
this.state.ingressesLoading = true;
|
this.state.ingressesLoading = true;
|
||||||
try {
|
try {
|
||||||
const namespace = this.pool.Namespace.Name;
|
const namespace = this.pool.Namespace.Name;
|
||||||
this.allIngresses = await this.KubernetesIngressService.get();
|
this.allIngresses = await this.KubernetesIngressService.get(this.state.hasWriteAuthorization ? '' : namespace);
|
||||||
this.ingresses = _.filter(this.allIngresses, { Namespace: namespace });
|
this.ingresses = _.filter(this.allIngresses, { Namespace: namespace });
|
||||||
_.forEach(this.ingresses, (ing) => {
|
_.forEach(this.ingresses, (ing) => {
|
||||||
ing.Namespace = namespace;
|
ing.Namespace = namespace;
|
||||||
|
|
Loading…
Reference in New Issue