Hi !
It looks like setuid is called before setgid in main.go :
|
if err = syscall.Setuid(cfg.HAProxy.UID); err != nil { |
|
if err = syscall.Setgid(cfg.HAProxy.GID); err != nil { |
I think that this makes it impossible to set both UID to an unprivileged user and GID, because setuid will be issued first and setgid will then produce the following error if the new user lacks the CAP_SETGID capability (even if the dataplane API was originally started as root) :
set gid: operation not permitted
Steps to reproduce
Simple Dockerfile using the official image haproxytech/haproxy-debian:s6-3.3.10 and creating an unprivileged user (but still running as root) :
FROM docker.io/haproxytech/haproxy-debian:s6-3.3.10
RUN groupadd --gid 1001 unprivileged && \
useradd --uid 1001 --gid unprivileged --shell /bin/false --no-create-home unprivileged
COPY haproxy.cfg dataplaneapi.yml /usr/local/etc/haproxy/
EXPOSE 80 5555
CMD ["/init"]
Basic dataplaneapi.yml file setting both uid and gid to 1001 :
config_version: 2
name: bug-reproduction
dataplaneapi:
host: 0.0.0.0
port: 5555
uid: 1001
gid: 1001
scheme:
- http
userlist:
userlist: dataplaneapi
haproxy:
config_file: /usr/local/etc/haproxy/haproxy.cfg
haproxy_bin: /usr/local/sbin/haproxy
reload:
reload_delay: 5
service_name: haproxy
reload_strategy: s6
log_targets:
- log_to: stdout
log_level: info
log_types:
- access
- app
Dummy haproxy.cfg :
global
log /dev/log local0
log /dev/log local1 notice
stats socket /var/run/haproxy.sock mode 660 level admin
daemon
maxconn 2000
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5s
timeout client 30s
timeout server 30s
userlist dataplaneapi
user admin insecure-password pwd
frontend http_front
bind *:80
default_backend web_servers
backend web_servers
balance roundrobin
server web1 192.168.1.101:80 check
server web2 192.168.1.102:80 check
listen stats
bind *:8404
stats enable
stats uri /stats
stats refresh 10s
Build :
podman build -t haproxy-dataplane-test .
Run :
podman run --name bug-reproduction -d -p 8080:80 -p 5555:5555 haproxy-dataplane-test
And check logs :
podman logs -f bug-reproduction
[...]
set gid: operation not permitted
[...]
Would a contribution to swap the order of setuid and setgid in main.go be welcome or is it something that can be addressed some other way ?
Thanks in advance for your time,
Benjamin
Hi !
It looks like
setuidis called beforesetgidinmain.go:dataplaneapi/cmd/dataplaneapi/main.go
Line 141 in efc5783
dataplaneapi/cmd/dataplaneapi/main.go
Line 148 in efc5783
I think that this makes it impossible to set both
UIDto an unprivileged user andGID, becausesetuidwill be issued first andsetgidwill then produce the following error if the new user lacks theCAP_SETGIDcapability (even if the dataplane API was originally started asroot) :Steps to reproduce
Simple Dockerfile using the official image
haproxytech/haproxy-debian:s6-3.3.10and creating an unprivileged user (but still running asroot) :Basic
dataplaneapi.ymlfile setting bothuidandgidto1001:Dummy
haproxy.cfg:Build :
podman build -t haproxy-dataplane-test .Run :
And check logs :
Would a contribution to swap the order of
setuidandsetgidinmain.gobe welcome or is it something that can be addressed some other way ?Thanks in advance for your time,
Benjamin