From e77ec9e84240ae0b24393a082e95c53cbc21f8a6 Mon Sep 17 00:00:00 2001 From: chengcheng Date: Fri, 17 Jul 2026 15:22:44 +0800 Subject: [PATCH] security(ci): bound runner resources --- deploy/ci/easyai-gateway-ci-v2-runner.service | 2 +- scripts/provision-ci-runner.sh | 14 +++++++++++++- tests/ci/pipeline-test.sh | 10 +++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/deploy/ci/easyai-gateway-ci-v2-runner.service b/deploy/ci/easyai-gateway-ci-v2-runner.service index 99556ee..3f4c9dc 100644 --- a/deploy/ci/easyai-gateway-ci-v2-runner.service +++ b/deploy/ci/easyai-gateway-ci-v2-runner.service @@ -12,7 +12,7 @@ Environment=RUNNER_SECURITY_OPTIONS= Environment=RUNNER_IMAGE_REF= EnvironmentFile=-/etc/easyai-gateway-ci-v2/runner.env ExecStartPre=-/usr/bin/docker rm --force easyai-gateway-ci-v2-runner -ExecStart=/usr/bin/docker run --rm --pull=never --name easyai-gateway-ci-v2-runner --privileged --pids-limit 4096 $RUNNER_SECURITY_OPTIONS --volume easyai-gateway-ci-v2-data:/data --volume /etc/easyai-gateway-ci-v2/config.yaml:/config.yaml:ro --volume /etc/easyai-gateway-ci-v2/daemon.json:/home/rootless/.config/docker/daemon.json:ro --volume /opt/easyai-gateway-ci:/opt/easyai-gateway-ci:ro --env CONFIG_FILE=/config.yaml --env DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns --env DOCKERD_ROOTLESS_ROOTLESSKIT_MTU=65520 --env DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=--pidns $RUNNER_IMAGE_REF +ExecStart=/usr/bin/docker run --rm --pull=never --name easyai-gateway-ci-v2-runner --privileged --cpus 2 --memory 2g --memory-swap 3g --pids-limit 1024 $RUNNER_SECURITY_OPTIONS --volume easyai-gateway-ci-v2-data:/data --volume /etc/easyai-gateway-ci-v2/config.yaml:/config.yaml:ro --volume /etc/easyai-gateway-ci-v2/daemon.json:/home/rootless/.config/docker/daemon.json:ro --volume /opt/easyai-gateway-ci:/opt/easyai-gateway-ci:ro --env CONFIG_FILE=/config.yaml --env DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns --env DOCKERD_ROOTLESS_ROOTLESSKIT_MTU=65520 --env DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=--pidns $RUNNER_IMAGE_REF ExecStop=-/usr/bin/docker stop --time 360 easyai-gateway-ci-v2-runner Restart=always RestartSec=5s diff --git a/scripts/provision-ci-runner.sh b/scripts/provision-ci-runner.sh index cff1918..6426a09 100755 --- a/scripts/provision-ci-runner.sh +++ b/scripts/provision-ci-runner.sh @@ -10,6 +10,10 @@ RUNNER_CONTAINER=easyai-gateway-ci-v2-runner LEGACY_BUILDER=${AI_GATEWAY_BUILDX_BUILDER:-easyai-gateway-ci} MIN_FREE_GIB=${CI_RUNNER_MIN_FREE_GIB:-8} MIN_POST_INSTALL_FREE_GIB=${CI_RUNNER_MIN_POST_INSTALL_FREE_GIB:-4} +RUNNER_CPUS=2 +RUNNER_MEMORY=2g +RUNNER_MEMORY_SWAP=3g +RUNNER_PIDS_LIMIT=1024 GITEA_RUNNER_VERSION=2.0.0 GO_VERSION=1.26.5 @@ -242,7 +246,9 @@ else set -- fi docker run --detach --rm --pull=never \ - --name "$PROBE_CONTAINER" --privileged --pids-limit 4096 "$@" \ + --name "$PROBE_CONTAINER" --privileged \ + --cpus "$RUNNER_CPUS" --memory "$RUNNER_MEMORY" \ + --memory-swap "$RUNNER_MEMORY_SWAP" --pids-limit "$RUNNER_PIDS_LIMIT" "$@" \ --volume "$RUNNER_VOLUME:/data" \ --volume /etc/easyai-gateway-ci-v2/daemon.json:/home/rootless/.config/docker/daemon.json:ro \ --volume "$PREFIX:$PREFIX:ro" \ @@ -262,6 +268,9 @@ until docker exec "$PROBE_CONTAINER" docker info >/dev/null 2>&1; do done [ "$(docker exec "$PROBE_CONTAINER" id -u)" = "1000" ] || \ fail "rootless Docker-in-Docker probe is not uid 1000" +[ "$(docker inspect --format '{{.HostConfig.Memory}}:{{.HostConfig.MemorySwap}}:{{.HostConfig.NanoCpus}}:{{.HostConfig.PidsLimit}}' "$PROBE_CONTAINER")" = \ + '2147483648:3221225472:2000000000:1024' ] || \ + fail "rootless Docker-in-Docker probe does not have the required aggregate resource limits" docker exec "$PROBE_CONTAINER" docker info --format '{{range .SecurityOptions}}{{println .}}{{end}}' | \ grep -Fq 'name=rootless' || fail "rootless Docker-in-Docker probe is not rootless" [ "$(docker exec "$PROBE_CONTAINER" docker info --format '{{.DockerRootDir}}')" = /data/docker ] || \ @@ -371,6 +380,9 @@ done fail "outer runner container is not using the rootless image user" [ "$(docker inspect --format '{{.HostConfig.Privileged}}' "$RUNNER_CONTAINER")" = "true" ] || \ fail "outer rootless DinD container is not privileged" +[ "$(docker inspect --format '{{.HostConfig.Memory}}:{{.HostConfig.MemorySwap}}:{{.HostConfig.NanoCpus}}:{{.HostConfig.PidsLimit}}' "$RUNNER_CONTAINER")" = \ + '2147483648:3221225472:2000000000:1024' ] || \ + fail "outer rootless DinD container does not have the required aggregate resource limits" if docker inspect --format '{{range .Mounts}}{{println .Source}}{{end}}' "$RUNNER_CONTAINER" | \ grep -Eq '/var/run/docker\.sock|/run/docker\.sock'; then fail "host Docker socket was mounted into the runner" diff --git a/tests/ci/pipeline-test.sh b/tests/ci/pipeline-test.sh index 3559ce9..d829728 100755 --- a/tests/ci/pipeline-test.sh +++ b/tests/ci/pipeline-test.sh @@ -117,7 +117,10 @@ grep -q '^CapabilityBoundingSet=$' "$runner_service" grep -Fq 'Requires=docker.service' "$runner_service" grep -Fq -- "--pull=never" "$runner_service" grep -Fq -- "--privileged" "$runner_service" -grep -Fq -- '--pids-limit 4096' "$runner_service" +grep -Fq -- '--pids-limit 1024' "$runner_service" +grep -Fq -- '--cpus 2' "$runner_service" +grep -Fq -- '--memory 2g' "$runner_service" +grep -Fq -- '--memory-swap 3g' "$runner_service" grep -Fq -- '--env DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=--pidns' "$runner_service" grep -Fq 'EnvironmentFile=-/etc/easyai-gateway-ci-v2/runner.env' "$runner_service" grep -Fq '$RUNNER_SECURITY_OPTIONS' "$runner_service" @@ -199,6 +202,11 @@ grep -Fq -- '--entrypoint dockerd-entrypoint.sh "$runner_runtime_image"' "$provi grep -Fq '/etc/easyai-gateway-ci-v2/daemon.json:/home/rootless/.config/docker/daemon.json:ro' "$provision" grep -Fq 'CI_NESTED_DOCKER_REGISTRY_MIRROR must be an HTTPS registry origin' "$provision" grep -Fq 'PROBE_CONTAINER="easyai-gateway-ci-v2-probe-$$"' "$provision" +grep -Fq -- '--pids-limit "$RUNNER_PIDS_LIMIT"' "$provision" +grep -Fq -- '--cpus "$RUNNER_CPUS"' "$provision" +grep -Fq -- '--memory "$RUNNER_MEMORY"' "$provision" +grep -Fq -- '--memory-swap "$RUNNER_MEMORY_SWAP"' "$provision" +grep -Fq "'2147483648:3221225472:2000000000:1024'" "$provision" grep -Fq -- '--entrypoint /usr/local/bin/gitea-runner' "$provision" grep -Fq 'shellcheck-v${SHELLCHECK_VERSION}.linux.x86_64.tar.xz' "$provision" grep -Fq 'docker-compose-linux-x86_64' "$provision"