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}" "$@"