@cryptotaxi247 / netdata-1 / commits / e2e20dad1

Safer container names (#6441)

* Allow building without pushing This enables easier local testing * Refactor fetching Docker container names to be safer Fixes #5680 * Wrap shell variable with quotes And change spaces to tabs * Make cgroup-name quieter * Make DOCKER_USR overridable * Update documentation to explain safe usage * Remove recommended image for docker socket proxy * Add capability to pass in a privileged GID * Fix some documentation typos * Update documentation to remove socket reference and clean up wording

Ian committed Jul 26, 2019 at 00:38 UTC e2e20dad1fc29dcd6bd76b6dc50c80045d0a2956
5 files changed +75 -73
collectors/cgroups.plugin/cgroup-name.sh.in
+13 -6
@@ -53,18 +53,25 @@ function docker_get_name_classic() {
53 }
54
55 function docker_get_name_api() {
56 - local id="${1}"
57 - if [ ! -S "${DOCKER_HOST}" ]; then
58 - warning "Can't find ${DOCKER_HOST}"
56 + local path="/containers/${1}/json"
57 + if [ -z "${DOCKER_HOST}" ]; then
58 + warning "No DOCKER_HOST is set"
59 return 1
60 fi
61 if ! command -v jq >/dev/null 2>&1; then
62 warning "Can't find jq command line tool. jq is required for netdata to retrieve docker container name using ${DOCKER_HOST} API, falling back to docker ps"
63 return 1
64 fi
65 -
66 - info "Running API command: /containers/${id}/json"
67 - JSON=$(echo -e "GET /containers/${id}/json HTTP/1.0\\r\\n" | nc -U "${DOCKER_HOST}" | grep '^{.*')
65 + if [ -S "${DOCKER_HOST}" ]; then
66 + info "Running API command: curl --unix-socket ${DOCKER_HOST} http://localhost${path}"
67 + JSON=$(curl -sS --unix-socket "${DOCKER_HOST}" "http://localhost${path}")
68 + elif [ "${DOCKER_HOST}" == "/var/run/docker.sock" ]; then
69 + warning "Docker socket was not found at ${DOCKER_HOST}"
70 + return 1
71 + else
72 + info "Running API command: curl ${DOCKER_HOST}${path}"
73 + JSON=$(curl -sS "${DOCKER_HOST}${path}")
74 + fi
75 NAME=$(echo "$JSON" | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
76 return 0
77 }
packaging/docker/Dockerfile
+5 -3
@@ -58,9 +58,11 @@ COPY --from=builder /app /
58 # Configure system
59 ARG NETDATA_UID=201
60 ARG NETDATA_GID=201
61 +ENV DOCKER_GRP netdata
62 +ENV DOCKER_USR netdata
63 RUN \
64 # provide judy installation to base image
63 - apk add make alpine-sdk && \
65 + apk add make alpine-sdk shadow && \
66 cd /judy-${JUDY_VER} && make install && cd / && \
67 # Clean the source stuff once judy is installed
68 rm -rf /judy-${JUDY_VER} && apk del make alpine-sdk && \
@@ -69,8 +71,8 @@ RUN \
71 chmod 4755 /usr/local/bin/fping && \
72 mkdir -p /var/log/netdata && \
73 # Add netdata user
72 - addgroup -g ${NETDATA_GID} -S netdata && \
73 - adduser -S -H -s /usr/sbin/nologin -u ${NETDATA_GID} -h /etc/netdata -G netdata netdata && \
74 + addgroup -g ${NETDATA_GID} -S "${DOCKER_GRP}" && \
75 + adduser -S -H -s /usr/sbin/nologin -u ${NETDATA_GID} -h /etc/netdata -G "${DOCKER_GRP}" "${DOCKER_USR}" && \
76 # Apply the permissions as described in
77 # https://github.com/netdata/netdata/wiki/netdata-security#netdata-directories
78 chown -R root:netdata /etc/netdata && \
packaging/docker/README.md
+39 -22
@@ -28,7 +28,6 @@ docker run -d --name=netdata \
28 -v /etc/group:/host/etc/group:ro \
29 -v /proc:/host/proc:ro \
30 -v /sys:/host/sys:ro \
31 - -v /var/run/docker.sock:/var/run/docker.sock:ro \
31 --cap-add SYS_PTRACE \
32 --security-opt apparmor=unconfined \
33 netdata/netdata
@@ -53,35 +52,53 @@ services:
52 - /etc/group:/host/etc/group:ro
53 - /proc:/host/proc:ro
54 - /sys:/host/sys:ro
56 - - /var/run/docker.sock:/var/run/docker.sock:ro
55 ```
56
57 If you don't want to use the apps.plugin functionality, you can remove the mounts of `/etc/passwd` and `/etc/group` (they are used to get proper user and group names for the monitored host) to get slightly better security.
58
59 ### Docker container names resolution
60
63 -If you want to have your container names resolved by netdata, you need to do two things:
64 -1) Make netdata user be part of the group that owns the socket.
65 - To achieve that just add environment variable `PGID=[GROUP NUMBER]` to the netdata container,
66 - where `[GROUP NUMBER]` is practically the group id of the group assigned to the docker socket, on your host.
67 - This group number can be found by running the following (if socket group ownership is docker):
68 - ```bash
69 - grep docker /etc/group | cut -d ':' -f 3
70 - ```
71 -
72 -2) Change docker socket access level to read/write like so:
73 - from
74 - ```
75 - /var/run/docker.sock:/var/run/docker.sock:ro
76 - ```
77 -
78 - change to
79 - ```
80 - /var/run/docker.sock:/var/run/docker.sock:rw
81 - ```
61 +There are a few options for resolving container names within netdata. Some methods of doing so will allow root access to your machine from within the container. Please read the following carefully.
62 +
63 +#### Docker Socket Proxy (Safest Option)
64 +
65 +Deploy a Docker socket proxy that accepts and filter out requests using something like [HAProxy](https://docs.netdata.cloud/docs/running-behind-haproxy/) so that it restricts connections to read-only access to the CONTAINERS endpoint.
66 +
67 +The reason it's safer to expose the socket to the proxy is because netdata has a TCP port exposed outside the Docker network. Access to the proxy container is limited to only within the network.
68 +
69 +#### Giving group access to Docker Socket (Less safe)
70 +
71 +**Important Note**: You should seriously consider the necessity of activating this option,
72 +as it grants to the netdata user access to the privileged socket connection of docker service and therefore your whole machine.
73 +
74 +If you want to have your container names resolved by Netdata, make the `netdata` user be part of the group that owns the socket.
75 +
76 +To achieve that just add environment variable `PGID=[GROUP NUMBER]` to the Netdata container,
77 +where `[GROUP NUMBER]` is practically the group id of the group assigned to the docker socket, on your host.
78 +
79 +This group number can be found by running the following (if socket group ownership is docker):
80 +
81 +```bash
82 +grep docker /etc/group | cut -d ':' -f 3
83 +```
84 +
85 +#### Running as root (Unsafe)
86
87 **Important Note**: You should seriously consider the necessity of activating this option,
84 -as it grants to the netdata user access to the privileged socket connection of docker service
88 +as it grants to the netdata user access to the privileged socket connection of docker service and therefore your whole machine.
89 +
90 +```yaml
91 +version: '3'
92 +services:
93 + netdata:
94 + image: netdata/netdata
95 + # ... rest of your config ...
96 + volumes:
97 + # ... other volumes ...
98 + - /var/run/docker.sock:/var/run/docker.sock:ro
99 + environment:
100 + - DOCKER_USR=root
101 +```
102
103 ### Pass command line options to Netdata
104
packaging/docker/build-test.sh
+11 -9
@@ -46,27 +46,29 @@ do
46 esac
47 done
48
49 -if [ -n "${REPOSITORY}" ] && [ -n "${VERSION}" ] && [ -n "${DOCKER_USERNAME}" ] && [ -n "${DOCKER_PWD}" ] ; then
49 +if [ -n "${REPOSITORY}" ]; then
50 if [ $DOBUILD -eq 1 ] ; then
51 - echo "Building ${VERSION} of ${REPOSITORY} container"
51 + echo "Building ${VERSION:-latest} of ${REPOSITORY} container"
52 docker run --rm --privileged multiarch/qemu-user-static:register --reset
53
54 # Build images using multi-arch Dockerfile.
55 - eval docker build --build-arg ARCH="amd64" --tag "${REPOSITORY}:${VERSION}" --file packaging/docker/Dockerfile ./
55 + eval docker build --build-arg ARCH="amd64" --tag "${REPOSITORY}:${VERSION:-latest}" --file packaging/docker/Dockerfile ./
56
57 # Create temporary docker CLI config with experimental features enabled (manifests v2 need it)
58 mkdir -p /tmp/docker
59 #echo '{"experimental":"enabled"}' > /tmp/docker/config.json
60 fi
61
62 - # Login to docker hub to allow futher operations
63 - echo "Logging into docker"
64 - echo "$DOCKER_PWD" | docker --config /tmp/docker login -u "$DOCKER_USERNAME" --password-stdin
62 + if [ -n "${DOCKER_USERNAME}" ] && [ -n "${DOCKER_PWD}" ] ; then
63 + # Login to docker hub to allow futher operations
64 + echo "Logging into docker"
65 + echo "$DOCKER_PWD" | docker --config /tmp/docker login -u "$DOCKER_USERNAME" --password-stdin
66
66 - echo "Pushing ${REPOSITORY}:${VERSION}"
67 - docker --config /tmp/docker push "${REPOSITORY}:${VERSION}"
67 + echo "Pushing ${REPOSITORY}:${VERSION}"
68 + docker --config /tmp/docker push "${REPOSITORY}:${VERSION}"
69 + fi
70 else
69 - echo "Missing parameter. REPOSITORY=${REPOSITORY} VERSION=${VERSION} DOCKER_USERNAME=${DOCKER_USERNAME} DOCKER_PWD=${DOCKER_PWD}"
71 + echo "Missing parameter. REPOSITORY=${REPOSITORY}"
72 printhelp
73 exit 1
74 fi
packaging/docker/run.sh
+7 -33
@@ -9,41 +9,15 @@ set -e
9
10 echo "Netdata entrypoint script starting"
11 if [ ${RESCRAMBLE+x} ]; then
12 - echo "Reinstalling all packages to get the latest Polymorphic Linux scramble"
13 - apk upgrade --update-cache --available
12 + echo "Reinstalling all packages to get the latest Polymorphic Linux scramble"
13 + apk upgrade --update-cache --available
14 fi
15
16 -create_group_and_assign_to_user() {
17 - local local_DOCKER_GROUP="$1"
18 - local local_DOCKER_GID="$2"
19 - local local_DOCKER_USR="$3"
20 -
21 - echo >&2 "Adding group with ID ${local_DOCKER_GID} and name '${local_DOCKER_GROUP}'"
22 - addgroup -g "${local_DOCKER_GID}" "${local_DOCKER_GROUP}" || echo >&2 "Could not add group ${local_DOCKER_GROUP} with ID ${local_DOCKER_GID}, its already there probably"
23 -
24 - echo >&2 "Adding user '${local_DOCKER_USR}' to group '${local_DOCKER_GROUP}/${local_DOCKER_GID}'"
25 - sed -i "s/:${local_DOCKER_GID}:$/:${local_DOCKER_GID}:${local_DOCKER_USR}/g" /etc/group
26 -
27 - # Make sure we use the right docker group
28 - GRP_TO_ASSIGN="$(grep ":x:${local_DOCKER_GID}:" /etc/group | cut -d':' -f1)"
29 - if [ -z "${GRP_TO_ASSIGN}" ]; then
30 - echo >&2 "Could not find group ID ${local_DOCKER_GID} in /etc/group. Check your logs and report it if this is an unrecovereable error"
31 - else
32 - echo >&2 "Group creation and assignment completed, netdata was assigned to group ${GRP_TO_ASSIGN}/${local_DOCKER_GID}"
33 - echo "${GRP_TO_ASSIGN}"
34 - fi
35 -}
36 -
37 -DOCKER_USR="netdata"
38 -DOCKER_SOCKET="/var/run/docker.sock"
39 -DOCKER_GROUP="docker"
40 -
41 -if [ -S "${DOCKER_SOCKET}" ] && [ -n "${PGID}" ]; then
42 - GRP=$(create_group_and_assign_to_user "${DOCKER_GROUP}" "${PGID}" "${DOCKER_USR}")
43 - if [ -n "${GRP}" ]; then
44 - echo "Adjusting ownership of mapped docker socket '${DOCKER_SOCKET}' to root:${GRP}"
45 - chown "root:${GRP}" "${DOCKER_SOCKET}" || echo "Failed to change ownership on docker socket, container name resolution might not work"
46 - fi
16 +if [ -n "${PGID}" ]; then
17 + echo "Creating docker group ${PGID}"
18 + addgroup -g "${PGID}" "docker" || echo >&2 "Could not add group docker with ID ${PGID}, its already there probably"
19 + echo "Assign netdata user to docker group ${PGID}"
20 + usermod -a -G ${PGID} ${DOCKER_USR} || echo >&2 "Could not add netdata user to group docker with ID ${PGID}"
21 fi
22
23 exec /usr/sbin/netdata -u "${DOCKER_USR}" -D -s /host -p "${NETDATA_PORT}" "$@"