Просмотр исходного кода

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 5 лет назад
Родитель
Сommit
e2e20dad1f

+ 13 - 6
collectors/cgroups.plugin/cgroup-name.sh.in

@@ -53,18 +53,25 @@ function docker_get_name_classic() {
 }
 }
 
 
 function docker_get_name_api() {
 function docker_get_name_api() {
-	local id="${1}"
-	if [ ! -S "${DOCKER_HOST}" ]; then
-		warning "Can't find ${DOCKER_HOST}"
+	local path="/containers/${1}/json"
+	if [ -z "${DOCKER_HOST}" ]; then
+		warning "No DOCKER_HOST is set"
 		return 1
 		return 1
 	fi
 	fi
 	if ! command -v jq >/dev/null 2>&1; then
 	if ! command -v jq >/dev/null 2>&1; then
 		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"
 		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"
 		return 1
 		return 1
 	fi
 	fi
-
-	info "Running API command: /containers/${id}/json"
-	JSON=$(echo -e "GET /containers/${id}/json HTTP/1.0\\r\\n" | nc -U "${DOCKER_HOST}" | grep '^{.*')
+	if [ -S "${DOCKER_HOST}" ]; then
+		info "Running API command: curl --unix-socket ${DOCKER_HOST} http://localhost${path}"
+		JSON=$(curl -sS --unix-socket "${DOCKER_HOST}" "http://localhost${path}")
+	elif [ "${DOCKER_HOST}" == "/var/run/docker.sock" ]; then
+		warning "Docker socket was not found at ${DOCKER_HOST}"
+		return 1
+	else
+		info "Running API command: curl ${DOCKER_HOST}${path}"
+		JSON=$(curl -sS "${DOCKER_HOST}${path}")
+	fi
 	NAME=$(echo "$JSON" | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
 	NAME=$(echo "$JSON" | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
 	return 0
 	return 0
 }
 }

+ 5 - 3
packaging/docker/Dockerfile

@@ -58,9 +58,11 @@ COPY --from=builder /app /
 # Configure system
 # Configure system
 ARG NETDATA_UID=201
 ARG NETDATA_UID=201
 ARG NETDATA_GID=201
 ARG NETDATA_GID=201
+ENV DOCKER_GRP netdata
+ENV DOCKER_USR netdata
 RUN \
 RUN \
     # provide judy installation to base image
     # provide judy installation to base image
-    apk add make alpine-sdk && \
+    apk add make alpine-sdk shadow && \
     cd /judy-${JUDY_VER} && make install && cd / && \
     cd /judy-${JUDY_VER} && make install && cd / && \
     # Clean the source stuff once judy is installed
     # Clean the source stuff once judy is installed
     rm -rf /judy-${JUDY_VER} && apk del make alpine-sdk && \
     rm -rf /judy-${JUDY_VER} && apk del make alpine-sdk && \
@@ -69,8 +71,8 @@ RUN \
     chmod 4755 /usr/local/bin/fping && \
     chmod 4755 /usr/local/bin/fping && \
     mkdir -p /var/log/netdata && \
     mkdir -p /var/log/netdata && \
     # Add netdata user
     # Add netdata user
-    addgroup -g ${NETDATA_GID} -S netdata && \
-    adduser -S -H -s /usr/sbin/nologin -u ${NETDATA_GID} -h /etc/netdata -G netdata netdata && \
+    addgroup -g ${NETDATA_GID} -S "${DOCKER_GRP}" && \
+    adduser -S -H -s /usr/sbin/nologin -u ${NETDATA_GID} -h /etc/netdata -G "${DOCKER_GRP}" "${DOCKER_USR}" && \
     # Apply the permissions as described in
     # Apply the permissions as described in
     # https://github.com/netdata/netdata/wiki/netdata-security#netdata-directories
     # https://github.com/netdata/netdata/wiki/netdata-security#netdata-directories
     chown -R root:netdata /etc/netdata && \
     chown -R root:netdata /etc/netdata && \

+ 39 - 22
packaging/docker/README.md

@@ -28,7 +28,6 @@ docker run -d --name=netdata \
   -v /etc/group:/host/etc/group:ro \
   -v /etc/group:/host/etc/group:ro \
   -v /proc:/host/proc:ro \
   -v /proc:/host/proc:ro \
   -v /sys:/host/sys:ro \
   -v /sys:/host/sys:ro \
-  -v /var/run/docker.sock:/var/run/docker.sock:ro \
   --cap-add SYS_PTRACE \
   --cap-add SYS_PTRACE \
   --security-opt apparmor=unconfined \
   --security-opt apparmor=unconfined \
   netdata/netdata
   netdata/netdata
@@ -53,35 +52,53 @@ services:
       - /etc/group:/host/etc/group:ro
       - /etc/group:/host/etc/group:ro
       - /proc:/host/proc:ro
       - /proc:/host/proc:ro
       - /sys:/host/sys:ro
       - /sys:/host/sys:ro
-      - /var/run/docker.sock:/var/run/docker.sock:ro
 ```
 ```
 
 
 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.
 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.
 
 
 ### Docker container names resolution
 ### Docker container names resolution
 
 
-If you want to have your container names resolved by netdata, you need to do two things:
-1) Make netdata user be part of the group that owns the socket.
-   To achieve that just add environment variable `PGID=[GROUP NUMBER]` to the netdata container,
-   where `[GROUP NUMBER]` is practically the group id of the group assigned to the docker socket, on your host.
-   This group number can be found by running the following (if socket group ownership is docker):
-   ```bash
-   grep docker /etc/group | cut -d ':' -f 3
-   ```
-
-2) Change docker socket access level to read/write like so:
-   from
-   ```
-   /var/run/docker.sock:/var/run/docker.sock:ro
-   ```
-
-   change to
-   ```
-   /var/run/docker.sock:/var/run/docker.sock:rw
-   ```
+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.
+
+#### Docker Socket Proxy (Safest Option)
+
+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.
+
+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.
+
+#### Giving group access to Docker Socket (Less safe)
+
+**Important Note**: You should seriously consider the necessity of activating this option,
+as it grants to the netdata user access to the privileged socket connection of docker service and therefore your whole machine.
+
+If you want to have your container names resolved by Netdata, make the `netdata` user be part of the group that owns the socket.
+
+To achieve that just add environment variable `PGID=[GROUP NUMBER]` to the Netdata container, 
+where `[GROUP NUMBER]` is practically the group id of the group assigned to the docker socket, on your host.
+
+This group number can be found by running the following (if socket group ownership is docker):
+
+```bash
+grep docker /etc/group | cut -d ':' -f 3
+```
+
+#### Running as root (Unsafe)
 
 
 **Important Note**: You should seriously consider the necessity of activating this option,
 **Important Note**: You should seriously consider the necessity of activating this option,
-as it grants to the netdata user access to the privileged socket connection of docker service
+as it grants to the netdata user access to the privileged socket connection of docker service and therefore your whole machine.
+
+```yaml
+version: '3'
+services:
+  netdata:
+    image: netdata/netdata
+    # ... rest of your config ...
+    volumes:
+      # ... other volumes ...
+      - /var/run/docker.sock:/var/run/docker.sock:ro
+    environment:
+      - DOCKER_USR=root
+```
 
 
 ### Pass command line options to Netdata 
 ### Pass command line options to Netdata 
 
 

+ 11 - 9
packaging/docker/build-test.sh

@@ -46,27 +46,29 @@ do
 	esac
 	esac
 done
 done
 
 
-if [ -n "${REPOSITORY}" ] && [ -n "${VERSION}" ] && [ -n "${DOCKER_USERNAME}" ] && [ -n "${DOCKER_PWD}" ] ; then
+if [ -n "${REPOSITORY}" ]; then
 	if [ $DOBUILD -eq 1 ] ; then
 	if [ $DOBUILD -eq 1 ] ; then
-		echo "Building ${VERSION} of ${REPOSITORY} container"
+		echo "Building ${VERSION:-latest} of ${REPOSITORY} container"
 		docker run --rm --privileged multiarch/qemu-user-static:register --reset
 		docker run --rm --privileged multiarch/qemu-user-static:register --reset
 
 
 		# Build images using multi-arch Dockerfile.
 		# Build images using multi-arch Dockerfile.
-		eval docker build --build-arg ARCH="amd64" --tag "${REPOSITORY}:${VERSION}" --file packaging/docker/Dockerfile ./
+		eval docker build --build-arg ARCH="amd64" --tag "${REPOSITORY}:${VERSION:-latest}" --file packaging/docker/Dockerfile ./
 
 
 		# Create temporary docker CLI config with experimental features enabled (manifests v2 need it)
 		# Create temporary docker CLI config with experimental features enabled (manifests v2 need it)
 		mkdir -p /tmp/docker
 		mkdir -p /tmp/docker
 		#echo '{"experimental":"enabled"}' > /tmp/docker/config.json
 		#echo '{"experimental":"enabled"}' > /tmp/docker/config.json
 	fi
 	fi
 
 
-	# Login to docker hub to allow futher operations
-	echo "Logging into docker"
-	echo "$DOCKER_PWD" | docker --config /tmp/docker login -u "$DOCKER_USERNAME" --password-stdin
+    if [ -n "${DOCKER_USERNAME}" ] && [ -n "${DOCKER_PWD}" ] ; then
+        # Login to docker hub to allow futher operations
+        echo "Logging into docker"
+        echo "$DOCKER_PWD" | docker --config /tmp/docker login -u "$DOCKER_USERNAME" --password-stdin
 
 
-	echo "Pushing ${REPOSITORY}:${VERSION}"
-	docker --config /tmp/docker push "${REPOSITORY}:${VERSION}"
+        echo "Pushing ${REPOSITORY}:${VERSION}"
+        docker --config /tmp/docker push "${REPOSITORY}:${VERSION}"
+    fi
 else
 else
-	echo "Missing parameter. REPOSITORY=${REPOSITORY} VERSION=${VERSION} DOCKER_USERNAME=${DOCKER_USERNAME} DOCKER_PWD=${DOCKER_PWD}"
+	echo "Missing parameter. REPOSITORY=${REPOSITORY}"
 	printhelp
 	printhelp
 	exit 1
 	exit 1
 fi
 fi

+ 7 - 33
packaging/docker/run.sh

@@ -9,41 +9,15 @@ set -e
 
 
 echo "Netdata entrypoint script starting"
 echo "Netdata entrypoint script starting"
 if [ ${RESCRAMBLE+x} ]; then
 if [ ${RESCRAMBLE+x} ]; then
-    echo "Reinstalling all packages to get the latest Polymorphic Linux scramble"
-    apk upgrade --update-cache --available
+	echo "Reinstalling all packages to get the latest Polymorphic Linux scramble"
+	apk upgrade --update-cache --available
 fi
 fi
 
 
-create_group_and_assign_to_user() {
-	local local_DOCKER_GROUP="$1"
-	local local_DOCKER_GID="$2"
-	local local_DOCKER_USR="$3"
-
-	echo >&2 "Adding group with ID ${local_DOCKER_GID} and name '${local_DOCKER_GROUP}'"
-	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"
-
-	echo >&2 "Adding user '${local_DOCKER_USR}' to group '${local_DOCKER_GROUP}/${local_DOCKER_GID}'"
-	sed -i "s/:${local_DOCKER_GID}:$/:${local_DOCKER_GID}:${local_DOCKER_USR}/g" /etc/group
-
-	# Make sure we use the right docker group
-	GRP_TO_ASSIGN="$(grep ":x:${local_DOCKER_GID}:" /etc/group | cut -d':' -f1)"
-	if [ -z "${GRP_TO_ASSIGN}" ]; then
-		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"
-	else
-		echo >&2 "Group creation and assignment completed, netdata was assigned to group ${GRP_TO_ASSIGN}/${local_DOCKER_GID}"
-		echo "${GRP_TO_ASSIGN}"
-	fi
-}
-
-DOCKER_USR="netdata"
-DOCKER_SOCKET="/var/run/docker.sock"
-DOCKER_GROUP="docker"
-
-if [ -S "${DOCKER_SOCKET}" ] && [ -n "${PGID}" ]; then
-	GRP=$(create_group_and_assign_to_user "${DOCKER_GROUP}" "${PGID}" "${DOCKER_USR}")
-	if [ -n "${GRP}" ]; then
-		echo "Adjusting ownership of mapped docker socket '${DOCKER_SOCKET}' to root:${GRP}"
-		chown "root:${GRP}" "${DOCKER_SOCKET}" || echo "Failed to change ownership on docker socket, container name resolution might not work"
-	fi
+if [ -n "${PGID}" ]; then
+    echo "Creating docker group ${PGID}"
+    addgroup -g "${PGID}" "docker" || echo >&2 "Could not add group docker with ID ${PGID}, its already there probably"
+    echo "Assign netdata user to docker group ${PGID}"
+    usermod -a -G ${PGID} ${DOCKER_USR} || echo >&2 "Could not add netdata user to group docker with ID ${PGID}"
 fi
 fi
 
 
 exec /usr/sbin/netdata -u "${DOCKER_USR}" -D -s /host -p "${NETDATA_PORT}" "$@"
 exec /usr/sbin/netdata -u "${DOCKER_USR}" -D -s /host -p "${NETDATA_PORT}" "$@"