YARN-8520. Document best practice for user management. Contributed by Eric Yang
This commit is contained in:
parent
a28624d2a4
commit
e7951c69cb
|
@ -296,7 +296,8 @@ owner as the container user. If the application owner is not a valid user
|
|||
in the Docker image, the application will fail. The container user is specified
|
||||
by the user's UID. If the user's UID is different between the NodeManager host
|
||||
and the Docker image, the container may be launched as the wrong user or may
|
||||
fail to launch because the UID does not exist.
|
||||
fail to launch because the UID does not exist. See
|
||||
[User Management in Docker Container](#user-management) section for more details.
|
||||
|
||||
Second, the Docker image must have whatever is expected by the application
|
||||
in order to execute. In the case of Hadoop (MapReduce or Spark), the Docker
|
||||
|
@ -412,6 +413,197 @@ the environment variable would be set to "/sys/fs/cgroup:/sys/fs/cgroup:ro".
|
|||
The destination path is not restricted, "/sys/fs/cgroup:/cgroup:ro" would also
|
||||
be valid given the example admin whitelist.
|
||||
|
||||
<a href="#user-management"></a>User Management in Docker Container
|
||||
-----------------------------------
|
||||
|
||||
YARN's Docker container support launches container processes using the uid:gid
|
||||
identity of the user, as defined on the NodeManager host. User and group name
|
||||
mismatches between the NodeManager host and container can lead to permission
|
||||
issues, failed container launches, or even security holes. Centralizing user and
|
||||
group management for both hosts and containers greatly reduces these risks. When
|
||||
running containerized applications on YARN, it is necessary to understand which
|
||||
uid:gid pair will be used to launch the container's process.
|
||||
|
||||
As an example of what is meant by uid:gid pair, consider the following. By
|
||||
default, in non-secure mode, YARN will launch processes as the user `nobody`
|
||||
(see the table at the bottom of
|
||||
[Using CGroups with YARN](./NodeManagerCgroups.html) for how the run as user is
|
||||
determined in non-secure mode). On CentOS based systems, the `nobody` user's uid
|
||||
is `99` and the `nobody` group is `99`. As a result, YARN will call `docker run`
|
||||
with `--user 99:99`. If the `nobody` user does not have the uid `99` in the
|
||||
container, the launch may fail or have unexpected results.
|
||||
|
||||
One exception to this rule is the use of Privileged Docker containers.
|
||||
Privileged containers will not set the uid:gid pair when launching the container
|
||||
and will honor the USER or GROUP entries in the Dockerfile. This allows running
|
||||
privileged containers as any user which has security implications. Please
|
||||
understand these implications before enabling Privileged Docker containers.
|
||||
|
||||
There are many ways to address user and group management. Docker, by default,
|
||||
will authenticate users against `/etc/passwd` (and `/etc/shadow`) within the
|
||||
container. Using the default `/etc/passwd` supplied in the Docker image is
|
||||
unlikely to contain the appropriate user entries and will result in launch
|
||||
failures. It is highly recommended to centralize user and group management.
|
||||
Several approaches to user and group management are outlined below.
|
||||
|
||||
### Static user management
|
||||
|
||||
The most basic approach to managing user and groups is to modify the user and
|
||||
group within the Docker image. This approach is only viable in non-secure mode
|
||||
where all container processes will be launched as a single known user, for
|
||||
instance `nobody`. In this case, the only requirement is that the uid:gid pair
|
||||
of the nobody user and group must match between the host and container. On a
|
||||
CentOS based system, this means that the nobody user in the container needs the
|
||||
UID `99` and the nobody group in the container needs GID `99`.
|
||||
|
||||
One approach to change the UID and GID is by leveraging `usermod` and
|
||||
`groupmod`. The following sets the correct UID and GID for the nobody
|
||||
user/group.
|
||||
```
|
||||
usermod -u 99 nobody
|
||||
groupmod -g 99 nobody
|
||||
```
|
||||
|
||||
This approach is not recommended beyond testing given the inflexibility to add
|
||||
users.
|
||||
|
||||
### Bind mounting
|
||||
|
||||
When organizations already have automation in place to create local users on
|
||||
each system, it may be appropriate to bind mount /etc/passwd and /etc/group
|
||||
into the container as an alternative to modifying the container image directly.
|
||||
To enable the ability to bind mount /etc/passwd and /etc/group, update
|
||||
`docker.allowed.ro-mounts` in `container-executor.cfg` to include those paths.
|
||||
When submitting the application, `YARN_CONTAINER_RUNTIME_DOCKER_MOUNTS` will
|
||||
need to include `/etc/passwd:/etc/passwd:ro` and `/etc/group:/etc/group:ro`.
|
||||
|
||||
There are several challenges with this bind mount approach that need to be
|
||||
considered.
|
||||
|
||||
1. Any users and groups defined in the image will be overwritten by the host's users and groups
|
||||
2. No users and groups can be added once the container is started, as /etc/passwd and /etc/group are immutible in the container. Do not mount these read-write as it can render the host inoperable.
|
||||
|
||||
This approach is not recommended beyond testing given the inflexibility to
|
||||
modify running containers.
|
||||
|
||||
### SSSD
|
||||
|
||||
An alternative approach that allows for centrally managing users and groups is
|
||||
SSSD. System Security Services Daemon (SSSD) provides access to different
|
||||
identity and authentication providers, such as LDAP or Active Directory.
|
||||
|
||||
The traditional schema for Linux authentication is as follows:
|
||||
```
|
||||
application -> libpam -> pam_authenticate -> pam_unix.so -> /etc/passwd
|
||||
```
|
||||
|
||||
If we use SSSD for user lookup, it becomes:
|
||||
```
|
||||
application -> libpam -> pam_authenticate -> pam_sss.so -> SSSD -> pam_unix.so -> /etc/passwd
|
||||
```
|
||||
|
||||
We can bind-mount the UNIX sockets SSSD communicates over into the container.
|
||||
This will allow the SSSD client side libraries to authenticate against the SSSD
|
||||
running on the host. As a result, user information does not need to exist in
|
||||
/etc/passwd of the docker image and will instead be serviced by SSSD.
|
||||
|
||||
Step by step configuration for host and container:
|
||||
|
||||
1. Host config
|
||||
|
||||
- Install packages
|
||||
```
|
||||
# yum -y install sssd-common sssd-proxy
|
||||
```
|
||||
- create a PAM service for the container.
|
||||
```
|
||||
# cat /etc/pam.d/sss_proxy
|
||||
auth required pam_unix.so
|
||||
account required pam_unix.so
|
||||
password required pam_unix.so
|
||||
session required pam_unix.so
|
||||
```
|
||||
- create SSSD config file, /etc/sssd/sssd.conf
|
||||
Please note that the permissions must be 0600 and the file must be owned by root:root.
|
||||
```
|
||||
# cat /etc/sssd/sssd/conf
|
||||
[sssd]
|
||||
services = nss,pam
|
||||
config_file_version = 2
|
||||
domains = proxy
|
||||
[nss]
|
||||
[pam]
|
||||
[domain/proxy]
|
||||
id_provider = proxy
|
||||
proxy_lib_name = files
|
||||
proxy_pam_target = sss_proxy
|
||||
```
|
||||
- start sssd
|
||||
```
|
||||
# systemctl start sssd
|
||||
```
|
||||
- verify a user can be retrieved with sssd
|
||||
```
|
||||
# getent passwd -s sss localuser
|
||||
```
|
||||
|
||||
2. Container setup
|
||||
|
||||
It's important to bind-mount the /var/lib/sss/pipes directory from the host to the container since SSSD UNIX sockets are located there.
|
||||
```
|
||||
-v /var/lib/sss/pipes:/var/lib/sss/pipes:rw
|
||||
```
|
||||
|
||||
3. Container config
|
||||
|
||||
All the steps below should be executed on the container itself.
|
||||
|
||||
- Install only the sss client libraries
|
||||
```
|
||||
# yum -y install sssd-client
|
||||
```
|
||||
|
||||
- make sure sss is configured for passwd and group databases in
|
||||
```
|
||||
/etc/nsswitch.conf
|
||||
```
|
||||
|
||||
- configure the PAM service that the application uses to call into SSSD
|
||||
```
|
||||
# cat /etc/pam.d/system-auth
|
||||
#%PAM-1.0
|
||||
# This file is auto-generated.
|
||||
# User changes will be destroyed the next time authconfig is run.
|
||||
auth required pam_env.so
|
||||
auth sufficient pam_unix.so try_first_pass nullok
|
||||
auth sufficient pam_sss.so forward_pass
|
||||
auth required pam_deny.so
|
||||
|
||||
account required pam_unix.so
|
||||
account [default=bad success=ok user_unknown=ignore] pam_sss.so
|
||||
account required pam_permit.so
|
||||
|
||||
password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
|
||||
password sufficient pam_unix.so try_first_pass use_authtok nullok sha512 shadow
|
||||
password sufficient pam_sss.so use_authtok
|
||||
password required pam_deny.so
|
||||
|
||||
session optional pam_keyinit.so revoke
|
||||
session required pam_limits.so
|
||||
-session optional pam_systemd.so
|
||||
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
|
||||
session required pam_unix.so
|
||||
session optional pam_sss.so
|
||||
```
|
||||
|
||||
- Save the docker image and use the docker image as base image for your applications.
|
||||
|
||||
- test the docker image launched in YARN environment.
|
||||
```
|
||||
$ id
|
||||
uid=5000(localuser) gid=5000(localuser) groups=5000(localuser),1337(hadoop)
|
||||
```
|
||||
|
||||
Privileged Container Security Consideration
|
||||
-------------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue