Докер как рут
Docker запускает свои контейнеры как root. Но нужна ли вашей рабочей нагрузке корневые права? Ответ редко. Тем не менее, ваши контейнеры по умолчанию продолжают работать от имени пользователя root. Это может иметь серьезные проблемы с безопасностью. Процесс, который выполняется внутри контейнера от имени пользователя root, фактически является процессом, выполняющимся от имени пользователя root на самом хосте. Это дает возможность злонамеренной попытке получить неограниченный доступ к самому хосту.
Вы можете проверить это самостоятельно, просто используйте следующую команду для любого изображения, которое вы обычно используете:
Оболочка
xxxxxxxxxx
1
$ kubectl run -i --tty hello-world --image=hello-world --restart=Never -- sh
2
/ # ps aux
3
PID USER TIME COMMAND
4
1 root 0:10 sh
Очевидно, что в качестве лучшей практики нам следует избегать запуска контейнеров с правами root. Итак, как мы можем это исправить, давайте посмотрим, как мы можем запустить контейнер как пользователь без полномочий root.
Добавление пользователя без прав root в Dockerfile
Создайте пользователя с таким количеством разрешений, которое требуется рабочей нагрузкой внутри контейнера. Вы можете создать пользователя с помощью команды RUN в Dockerfile самого изображения контейнера.
Dockerfile
xxxxxxxxxx
1
RUN groupadd --gid 5000 newuser \
2
&& useradd --home-dir /home/newuser --create-home --uid 5000 \
3
--gid 5000 --shell /bin/sh --skel /dev/null newuser
Выше строка кода создает пользователя, newuser
, вместе с домом и оболочки для пользователя. Теперь просто добавьте пользователя в свой Dockerfile, как в следующем примере:
Dockerfile
xxxxxxxxxx
1
FROM ubuntu:18.04
2
COPY . /myapp
3
RUN make /myapp
4
...
5
USER newuser
6
CMD python /myapp/hello.py
Начиная со строки 5, каждая команда запускается от имени пользователя, newuser
а не от имени пользователя root. Просто, не правда ли?
Но мы не всегда используем только наши собственные изображения; мы также используем много сторонних изображений и не сможем внедрить в них непривилегированного пользователя, как описано выше.
Эти сторонние образы Docker по умолчанию будут работать от имени пользователя root, если мы не будем с ними что-то делать. Если вы используете изображение из не очень популярного источника, то оно может даже быть встроено с помощью вредоносной команды, которая может поставить под угрозу безопасность вашего кластера.
К нам приходят на помощь контекст безопасности Kubernetes и политики безопасности pod.
Вам также может понравиться:
Обеспечение безопасности ваших контейнеров Docker .
Используйте Pod Security Context
Вы можете использовать контекст безопасности модуля, чтобы ограничить выполнение модуля конкретным пользователем без полномочий root. Чтобы указать эти параметры безопасности для модуля, добавьте securityContext
поле в спецификации модуля.
YAML
xxxxxxxxxx
1
apiVersion v1
2
kind Pod
3
metadata
4
name my-pod
5
spec
6
securityContext
7
runAsUser5000
8
runAsGroup5000
9
volumes
10
name my-vol
11
emptyDir
12
containers
13
name my-container
14
image hello-world
15
command"sh" "-c" "sleep 10 m"
16
volumeMounts
17
name my-vol
18
mountPath /data/hello
19
securityContext
20
allowPrivilegeEscalationfalse
В приведенной выше спецификации runAsUser
указывает, что любой контейнер внутри модуля будет работать 5000
только с идентификатором пользователя . Это пользователь, которого мы создали специально как непривилегированный пользователь. runAsGroup
Определяет идентификатор группы всех процессов. Если мы не упомянем об этом, то идентификатор группы будет root (0).
Теперь вы можете создать этот модуль и проверить процессы, запущенные внутри контейнера:
Оболочка
xxxxxxxxxx
1
$ kubectl apply -f my-pod.yaml
2
$ kubectl exec -it my-pod – sh
3
ps
4
PID USER TIME COMMAND
6
1 5000 0:00 sleep 10 m
7
6 5000 0:00 sh
Как вы можете видеть выше, PID 1 запускается как userID 5000, а не как root.
Использовать политику безопасности Kubernetes Pod
Kubernetes Pod Политика безопасности определяет условия, с которыми модуль должен работать; в противном случае он не будет подготовлен в кластере. Другими словами, если эти условия не будут выполнены, Kubernetes будет препятствовать запуску стручка.
Пример PodSecurityPolicy приведен ниже:
YAML
xxxxxxxxxx
1
apiVersion policy/v1beta1
2
kind PodSecurityPolicy
3
metadata
4
name my-psp
5
spec
6
privilegedfalse
7
#Required to prevent escalations to root.
8
allowPrivilegeEscalationfalse
9
allowedCapabilities
10
'*'
11
volumes
12
'nfs'
13
hostNetworktrue
14
hostPorts
15
min8000
16
max8000
17
hostIPCtrue
18
hostPIDtrue
19
runAsUser
20
#Require the container to run without root.
21
rule'MustRunAsNonRoot'
22
seLinux
23
rule'RunAsAny'
24
supplementalGroups
25
rule'RunAsAny'
26
fsGroup
27
rule'RunAsAny'
Эта политика безопасности обеспечивает следующее:
- Запретить запуск контейнера в привилегированном режиме.
- Ограничить контейнер, которому нужен рут.
- Ограничьте контейнер, который обращается к другим файлам, кроме тома NFS.
- Разрешить только контейнерам доступ к хост-порту 100.
Активировать политику:
Оболочка
xxxxxxxxxx
1
$ kubectl create -f my-psp.yaml
Проверьте политику:
Оболочка
xxxxxxxxxx
1
$ kubectl get psp
2
NAME PRIV RUNASUSER FSGROUP SELINUX VOLUMES
3
My-psp false MustRunAsNonRoot RunAsAny RunAsAny [nfs]
4
Теперь, когда политика создана, вы можете проверить ее, попытавшись запустить контейнер с привилегиями root.
xxxxxxxxxx
1
$ kubectl run --image=my-root-container
Политика безопасности модуля запрещает запуск и выдает сообщение об ошибке:
Оболочка
xxxxxxxxxx
1
$ kubectl get pods
2
NAME READY STATUS
3
my-root-pod 0/1 container has runAsNonRoot and image will run as root
4
Заключение
В этой статье я выделил риск, связанный с запуском контейнера Docker с настройками по умолчанию для пользователя root. Я также предложил несколько способов преодолеть этот риск.
- Если вы запускаете пользовательский образ, создайте нового непривилегированного пользователя и укажите его в своем Dockerfile.
- Если вы используете сторонние изображения, вы можете установить контекст безопасности на уровне контейнера или контейнера.
- Еще один способ - создать политику безопасности pod, которая не позволит ни одному контейнеру работать с привилегиями root.