fix(container): prevent user from editing the portainer container it self EE-917 (#6093)

* fix(container): prevent from editing portainer container

* fix(container): prevent from editing portainer container

* Missing kill operation

* fix(container): enhance creating stack from template

* fix(docker): prevent user from editing the portainer container itself EE-917

* fix(docker): enhance code style

* fix(container): fix issues from code review

* fix(container): enhance creating stack from template

* fix(container): some code review issues

* fix(container): disable leave network when the container is portainer

* fix(container): disable leave network when the container is portainer
pull/5999/head^2
Hao Zhang 2021-12-02 08:41:05 +08:00 committed by GitHub
parent d2fe76368a
commit 42e782452c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 74 additions and 13 deletions

View File

@ -52,9 +52,9 @@ func (handler *Handler) proxyRequestsToDockerAPI(w http.ResponseWriter, r *http.
id := strconv.Itoa(endpointID)
prefix := "/" + id + "/agent/docker";
prefix := "/" + id + "/agent/docker"
if !strings.HasPrefix(r.URL.Path, prefix) {
prefix = "/" + id + "/docker";
prefix = "/" + id + "/docker"
}
http.StripPrefix(prefix, proxy).ServeHTTP(w, r)

View File

@ -69,6 +69,11 @@ func (transport *Transport) containerListOperation(response *http.Response, exec
}
}
responseArray, err = transport.applyPortainerContainers(responseArray)
if err != nil {
return err
}
return utils.RewriteResponse(response, responseArray, http.StatusOK)
}
@ -88,6 +93,8 @@ func (transport *Transport) containerInspectOperation(response *http.Response, e
labelsObjectSelector: selectorContainerLabelsFromContainerInspectOperation,
}
responseObject, _ = transport.applyPortainerContainer(responseObject)
return transport.applyAccessControlOnResource(resourceOperationParameters, responseObject, response, executor)
}

View File

@ -0,0 +1,42 @@
package docker
import (
"os"
)
var portainerContainerId string
func init() {
// use hostname as the current portainer id
// Reference issue: JIRA EE-917
// https://social.msdn.microsoft.com/Forums/en-US/5e5bff27-7511-4fb2-9ffa-207520d0ffb8/how-to-gain-windows-container-id-in-windows-container?forum=windowscontainers
// Because Windows container cannot obtain container ID from /proc/self/cgroups like linux container,
// as a workaround, we currently use hostname as container ID.
portainerContainerId, _ = os.Hostname()
}
func (transport *Transport) applyPortainerContainers(resources []interface{}) ([]interface{}, error) {
decoratedResourceData := make([]interface{}, 0)
for _, resource := range resources {
responseObject, ok := resource.(map[string]interface{})
if !ok {
decoratedResourceData = append(decoratedResourceData, resource)
continue
}
responseObject, _ = transport.applyPortainerContainer(responseObject)
decoratedResourceData = append(decoratedResourceData, responseObject)
}
return decoratedResourceData, nil
}
func (transport *Transport) applyPortainerContainer(resourceObject map[string]interface{}) (map[string]interface{}, error) {
resourceId, ok := resourceObject["Id"].(string)
if !ok {
return resourceObject, nil
}
if len(resourceId) >= 12 && resourceId[0:12] == portainerContainerId {
resourceObject["IsPortainer"] = true
}
return resourceObject, nil
}

View File

@ -64,7 +64,7 @@
<button
type="button"
class="btn btn-xs btn-danger"
ng-disabled="$ctrl.leaveNetworkActionInProgress"
ng-disabled="$ctrl.leaveNetworkActionInProgress || $ctrl.container.IsPortainer"
button-spinner="$ctrl.leaveNetworkActionInProgress"
ng-click="$ctrl.leaveNetworkAction($ctrl.container, key)"
>

View File

@ -217,7 +217,7 @@
ng-if="!$ctrl.offlineMode"
authorization="DockerContainerStart, DockerContainerStop, DockerContainerKill, DockerContainerRestart, DockerContainerPause, DockerContainerUnpause, DockerContainerDelete, DockerContainerCreate"
>
<input id="select_{{ $index }}" type="checkbox" ng-model="item.Checked" ng-click="$ctrl.selectItem(item, $event)" />
<input id="select_{{ $index }}" type="checkbox" ng-model="item.Checked" ng-click="$ctrl.selectItem(item, $event)" ng-disabled="!$ctrl.allowSelection(item)" />
<label for="select_{{ $index }}"></label>
</span>
<a ng-if="!$ctrl.offlineMode" ui-sref="docker.containers.container({ id: item.Id, nodeName: item.NodeName })" title="{{ item | containername }}">{{

View File

@ -76,6 +76,10 @@ angular.module('portainer.docker').controller('ContainersDatatableController', [
},
};
this.allowSelection = function (item) {
return !item.IsPortainer;
};
this.onColumnVisibilityChange = onColumnVisibilityChange.bind(this);
function onColumnVisibilityChange(columns) {
this.columnVisibility.columns = columns;

View File

@ -45,6 +45,8 @@ export function ContainerViewModel(data) {
}
this.Mounts = data.Mounts;
this.IsPortainer = data.IsPortainer;
this.Ports = [];
if (data.Ports) {
for (var i = 0; i < data.Ports.length; ++i) {
@ -139,4 +141,5 @@ export function ContainerDetailsViewModel(data) {
if (data.Portainer && data.Portainer.ResourceControl) {
this.ResourceControl = new ResourceControlViewModel(data.Portainer.ResourceControl);
}
this.IsPortainer = data.IsPortainer;
}

View File

@ -168,7 +168,8 @@
<button
type="button"
class="btn btn-primary btn-sm"
ng-disabled="state.actionInProgress || !formValues.RegistryModel.Image || (!formValues.RegistryModel.Registry && fromContainer)"
ng-disabled="state.actionInProgress || !formValues.RegistryModel.Image || (!formValues.RegistryModel.Registry && fromContainer)
|| (fromContainer.IsPortainer && fromContainer.Name === '/' + config.name)"
ng-click="create()"
button-spinner="state.actionInProgress"
>

View File

@ -14,25 +14,29 @@
<rd-widget-header icon="fa-cogs" title-text="Actions"></rd-widget-header>
<rd-widget-body classes="padding">
<div class="btn-group" role="group" aria-label="...">
<button authorization="DockerContainerStart" class="btn btn-success btn-sm" ng-click="start()" ng-disabled="container.State.Running"
<button authorization="DockerContainerStart" class="btn btn-success btn-sm" ng-click="start()" ng-disabled="container.State.Running || container.IsPortainer"
><i class="fa fa-play space-right" aria-hidden="true"></i>Start</button
>
<button authorization="DockerContainerStop" class="btn btn-danger btn-sm" ng-click="stop()" ng-disabled="!container.State.Running"
<button authorization="DockerContainerStop" class="btn btn-danger btn-sm" ng-click="stop()" ng-disabled="!container.State.Running || container.IsPortainer"
><i class="fa fa-stop space-right" aria-hidden="true"></i>Stop</button
>
<button authorization="DockerContainerKill" class="btn btn-danger btn-sm" ng-click="kill()" ng-disabled="!container.State.Running"
<button authorization="DockerContainerKill" class="btn btn-danger btn-sm" ng-click="kill()" ng-disabled="!container.State.Running || container.IsPortainer"
><i class="fa fa-bomb space-right" aria-hidden="true"></i>Kill</button
>
<button authorization="DockerContainerRestart" class="btn btn-primary btn-sm" ng-click="restart()" ng-disabled="!container.State.Running"
<button authorization="DockerContainerRestart" class="btn btn-primary btn-sm" ng-click="restart()" ng-disabled="!container.State.Running || container.IsPortainer"
><i class="fa fa-sync space-right" aria-hidden="true"></i>Restart</button
>
<button authorization="DockerContainerPause" class="btn btn-primary btn-sm" ng-click="pause()" ng-disabled="!container.State.Running || container.State.Paused"
<button
authorization="DockerContainerPause"
class="btn btn-primary btn-sm"
ng-click="pause()"
ng-disabled="!container.State.Running || container.State.Paused || container.IsPortainer"
><i class="fa fa-pause space-right" aria-hidden="true"></i>Pause</button
>
<button authorization="DockerContainerUnpause" class="btn btn-primary btn-sm" ng-click="unpause()" ng-disabled="!container.State.Paused"
<button authorization="DockerContainerUnpause" class="btn btn-primary btn-sm" ng-click="unpause()" ng-disabled="!container.State.Paused || container.IsPortainer"
><i class="fa fa-play space-right" aria-hidden="true"></i>Resume</button
>
<button authorization="DockerContainerDelete" class="btn btn-danger btn-sm" ng-click="confirmRemove()"
<button authorization="DockerContainerDelete" class="btn btn-danger btn-sm" ng-click="confirmRemove()" ng-disabled="container.IsPortainer"
><i class="fa fa-trash-alt space-right" aria-hidden="true"></i>Remove</button
>
</div>
@ -40,7 +44,7 @@
<button
type="button"
class="btn btn-danger btn-sm"
ng-disabled="state.recreateContainerInProgress"
ng-disabled="state.recreateContainerInProgress || container.IsPortainer"
ng-click="recreate()"
button-spinner="state.recreateContainerInProgress"
>