Es muy molesto tener esta limitación en mi cuadro de desarrollo, cuando no habrá ningún usuario que no sea yo.
Soy consciente de las soluciones estándar , pero ninguna de ellas hace exactamente lo que quiero:
- authbind (la versión en las pruebas de Debian, 1.0, solo admite IPv4)
- Uso del objetivo REDIRECT de iptables para redirigir un puerto bajo a un puerto alto (la tabla "nat" aún no está implementada para ip6tables, la versión IPv6 de iptables)
- sudo (Ejecutar como root es lo que estoy tratando de evitar)
- SELinux (o similar). (Este es solo mi cuadro de desarrollo, no quiero introducir mucha complejidad adicional).
¿Existe alguna sysctl
variable simple para permitir que los procesos no root se unan a puertos "privilegiados" (puertos menores de 1024) en Linux, o simplemente no tengo suerte?
EDITAR: en algunos casos, puede usar capacidades para hacer esto.
Respuestas:
Bien, gracias a las personas que señalaron el sistema de
CAP_NET_BIND_SERVICE
capacidades y la capacidad. Si tiene un kernel reciente, de hecho es posible usarlo para iniciar un servicio como no raíz pero enlazar puertos bajos. La respuesta corta es que haces:Y luego, en cualquier momento que
program
se ejecute, tendrá laCAP_NET_BIND_SERVICE
capacidad.setcap
está en el paquete debianlibcap2-bin
.Ahora para las advertencias:
program
que tenga privilegios elevados comosetcap
osuid
. Entonces, siprogram
usa los suyos.../lib/
, es posible que deba buscar otra opción, como el reenvío de puertos.Recursos:
setcap
.Nota: RHEL primero agregó esto en v6 .
fuente
/usr/bin/java
y luego abriría la capacidad a cualquier aplicación Java que se ejecute en el sistema. Las capacidades demasiado malas tampoco se pueden establecer por usuario./etc/security/capability.conf
Debian / Ubuntu alguna ayuda?Puede hacer una redirección de puerto. Esto es lo que hago para un servidor de políticas Silverlight que se ejecuta en un cuadro de Linux
fuente
/etc/network/if-up.d/firewall
.La forma estándar es hacerlos "setuid" para que se inicien como root, y luego descarten ese privilegio de root tan pronto como se unan al puerto pero antes de que comiencen a aceptar conexiones a él. Puede ver buenos ejemplos de eso en el código fuente de Apache e INN. Me dicen que Lighttpd es otro buen ejemplo.
Otro ejemplo es Postfix, que utiliza múltiples demonios que se comunican a través de tuberías, y solo uno o dos de ellos (que hacen muy poco, excepto aceptar o emitir bytes) se ejecutan como root y el resto se ejecuta con un privilegio menor.
fuente
binfmt_misc
su bandera 'C'; no estoy seguro de los demás.)O parchear su núcleo y eliminar el cheque.
(Opción de último recurso, no recomendado).
En
net/ipv4/af_inet.c
, elimine las dos líneas que leeny el kernel ya no verificará los puertos privilegiados.
fuente
Puede configurar un túnel SSH local, por ejemplo, si desea que el puerto 80 llegue a su aplicación vinculada a 3000:
Esto tiene la ventaja de trabajar con servidores de script y ser muy simple.
fuente
sudo nc -l 80 | nc localhost 3000
Actualización 2017:
Use authbind
Mucho mejor que CAP_NET_BIND_SERVICE o un kernel personalizado.
Authbind otorga confianza al usuario / grupo y proporciona control sobre el acceso por puerto, y es compatible con IPv4 e IPv6 (últimamente se ha agregado compatibilidad con IPv6).
Instalar en pc:
apt-get install authbind
Configure el acceso a los puertos relevantes, por ejemplo, 80 y 443 para todos los usuarios y grupos:
Ejecute su comando vía
authbind
(opcionalmente especificando
--deep
u otros argumentos, vea la página del manual):p.ej
Como seguimiento a la fabulosa (no recomendada de Joshua a menos que sepas lo que haces) recomendación para hackear el kernel:
Lo publiqué por primera vez aquí .
Simple. Con un núcleo normal o antiguo, no lo hace.
Como señalaron otros, iptables puede reenviar un puerto.
Como también señalaron otros, CAP_NET_BIND_SERVICE también puede hacer el trabajo.
Por supuesto, CAP_NET_BIND_SERVICE fallará si inicia su programa desde un script, a menos que configure el límite en el intérprete de shell, lo cual no tiene sentido, podría ejecutar su servicio como root ...
por ejemplo, para Java, debe aplicarlo a la JVM JAVA
Obviamente, eso significa que cualquier programa Java puede enlazar puertos del sistema.
Dito para mono / .NET.
También estoy bastante seguro de que xinetd no es la mejor de las ideas.
Pero dado que ambos métodos son hacks, ¿por qué no simplemente levantar el límite levantando la restricción?
Nadie dijo que tenía que ejecutar un núcleo normal, por lo que puede ejecutar el suyo.
Simplemente descargue la fuente del último kernel (o el mismo que tiene actualmente). Luego, vas a:
Ahí buscas esta línea
y cambiarlo a
si no desea tener una situación ssh insegura, modifíquela a esto: #define PROT_SOCK 24
En general, usaría la configuración más baja que necesite, por ejemplo, 79 para http, o 24 cuando use SMTP en el puerto 25.
Eso ya es todo.
Compile el núcleo e instálelo.
Reiniciar.
Terminado: ese límite estúpido se ha ido, y eso también funciona para los scripts.
Así es como compila un núcleo:
https://help.ubuntu.com/community/Kernel/Compile
En pocas palabras, use iptables si desea mantenerse seguro, compile el kernel si desea asegurarse de que esta restricción nunca lo moleste nuevamente.
fuente
Las capacidades de archivo no son ideales, porque pueden romperse después de una actualización del paquete.
La solución ideal, en mi humilde opinión, debería ser la capacidad de crear un shell con un
CAP_NET_BIND_SERVICE
conjunto heredable .Aquí hay una forma algo complicada de hacer esto:
capsh
La utilidad se puede encontrar en el paquete libcap2-bin en las distribuciones Debian / Ubuntu. Esto es lo que pasa:sg
cambia la identificación efectiva del grupo a la del usuario daemon. Esto es necesario porquecapsh
deja GID sin cambios y definitivamente no lo queremos.$DAEMONUSER
--keep=1
), excepto heredablescap_net_bind_service
El resultado es un proceso con usuario y grupo especificados, y
cap_net_bind_service
privilegios.Como ejemplo, una línea del
ejabberd
script de inicio:fuente
capsh
hacer otra cosa que "no puedo ejecutar el archivo binario" cuando uso las opciones--
o==
. Me pregunto qué me estoy perdiendo.--
se pasa a/bin/bash
, por lo que es posible que desee probar-c 'your command'
. Por desgracia, parece que estoy experimentando el mismo problema que @Cyberax, porque obtengo un "permiso denegado" cuando intentobind
.--gid
en lugar desg
(o--user
qué conjuntos--uid
,--gid
y--groups
):sudo capsh --caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' --keep=1 --user="$service_user" --addamb=cap_net_bind_service -- -c 'exec $service $service_args'
Por alguna razón, nadie menciona acerca de reducir sysctl net.ipv4.ip_unprivileged_port_start al valor que necesita. Ejemplo: necesitamos vincular nuestra aplicación al puerto 443.
Algunos pueden decir que existe un posible problema de seguridad: los usuarios no privilegiados ahora pueden unirse a los otros puertos privilegiados (444-1024). Pero puede resolver este problema fácilmente con iptables, bloqueando otros puertos:
Comparación con otros métodos. Este método:
Dependiendo de la situación, elegiría entre sysctl, CAP, authbind e iptables-redirect. Y esto es genial porque tenemos tantas opciones.
fuente
Otras dos posibilidades simples:
Hay una solución antigua (pasada de moda) para "un demonio que se une a un puerto bajo y controla las manos de su demonio". Se llama inetd (o xinetd). Los contras son:
Pros:
Otra alternativa: un proxy pirateado (netcat o incluso algo más robusto ) desde el puerto privilegiado a algún puerto arbitrario de alto número donde puede ejecutar su demonio de destino. (Netcat obviamente no es una solución de producción, sino "solo mi caja de desarrollo", ¿verdad?). De esta manera, podría continuar utilizando una versión de su servidor con capacidad de red, solo necesitaría root / sudo para iniciar el proxy (en el arranque), no dependería de capacidades complejas / potencialmente frágiles.
fuente
Mi "solución estándar" usa socat como redirector de espacio de usuario:
Tenga en cuenta que esto no escalará, la bifurcación es costosa pero es la forma en que funciona socat.
fuente
Linux admite capacidades para admitir permisos más específicos que simplemente "esta aplicación se ejecuta como root". Una de esas capacidades es la
CAP_NET_BIND_SERVICE
que se trata de vincular a un puerto privilegiado (<1024).Desafortunadamente, no sé cómo explotar eso para ejecutar una aplicación como no root mientras la sigo dando
CAP_NET_BIND_SERVICE
(probablemente usandosetcap
, pero seguramente habrá una solución existente para esto).fuente
Sé que esta es una vieja pregunta, pero ahora con núcleos recientes (> = 4.3) finalmente hay una buena respuesta a esto: capacidades ambientales.
La respuesta rápida es tomar una copia de la última versión (aún no publicada) de libcap de git y compilarla. Copie el
progs/capsh
binario resultante en alguna parte (/usr/local/bin
es una buena opción). Luego, como root, inicie su programa conEn orden, somos
cap_net_bind_service
capacidad a los conjuntos heredados y ambientalesbash -c 'your-command'
(ya quecapsh
automáticamente comienza a golpear con los argumentos después--
)Aquí pasan muchas cosas debajo del capó.
En primer lugar, nos estamos ejecutando como root, por lo que, de forma predeterminada, obtenemos un conjunto completo de capacidades. Se incluye en esto la capacidad de cambiar uid & gid con las llamadas al sistema
setuid
ysetgid
. Sin embargo, normalmente cuando un programa hace esto, pierde su conjunto de capacidades, esto es para que la antigua forma de eliminar la raízsetuid
aún funcione. El--keep=1
indicador le indicacapsh
que emita laprctl(PR_SET_KEEPCAPS)
llamada al sistema, que deshabilita la pérdida de capacidades al cambiar de usuario. El cambio real de usuarios porcapsh
ocurre con la--user
bandera, que se ejecutasetuid
ysetgid
.El siguiente problema que debemos resolver es cómo establecer capacidades de una manera que continúe después de que
exec
nuestros hijos. El sistema de capacidades siempre ha tenido un conjunto de capacidades 'heredado', que es "un conjunto de capacidades preservadas en un execve (2)" [ capacidades (7) ]. Si bien esto suena como que resuelve nuestro problema (solo establece lacap_net_bind_service
capacidad de heredado, ¿verdad?), Esto en realidad solo se aplica a procesos privilegiados, y nuestro proceso ya no es privilegiado, porque ya cambiamos de usuario (con la--user
bandera).El nuevo conjunto de capacidades ambientales soluciona este problema: es "un conjunto de capacidades que se conservan en un execve (2) de un programa que no tiene privilegios". Al poner
cap_net_bind_service
el entorno, cuando elcapsh
ejecutivo es nuestro programa de servidor, nuestro programa heredará esta capacidad y podrá vincular a los oyentes a puertos bajos.Si está interesado en obtener más información, la página del manual de capacidades explica esto con gran detalle. Correr
capsh
a travésstrace
también es muy informativo!fuente
--addamb
bandera se introdujo con libcap 2.26. Mi sistema tenía 2.25 y tuve que construir desde la fuente.TLDR: Para "la respuesta" (tal como la veo), salte a la parte >> TLDR << en esta respuesta.
De acuerdo, lo he descubierto (de verdad esta vez), la respuesta a esta pregunta, y esta respuesta mía también es una forma de disculparme por promover otra respuesta (tanto aquí como en Twitter) que pensé que era "la mejor ", pero después de intentarlo, descubrí que me había equivocado al respecto. Aprenda de mi error, niños: ¡no promocionen algo hasta que lo hayan intentado ustedes mismos!
Nuevamente, revisé todas las respuestas aquí. He probado algunos de ellos (y elegí no probar otros porque simplemente no me gustaron las soluciones). Pensé que la solución era utilizar
systemd
con susCapabilities=
yCapabilitiesBindingSet=
ajustes. Después de luchar con esto por un tiempo, descubrí que esta no es la solución porque:¡Las capacidades están destinadas a restringir los procesos raíz!
Como el OP declaró sabiamente, siempre es mejor evitar eso (¡para todos tus demonios si es posible!).
No puede usar las opciones relacionadas con Capacidades con
User=
yGroup=
ensystemd
archivos de unidad, porque las capacidades SIEMPRE se restablecen cuandoexecev
(o como se llame la función). En otras palabras, cuando sesystemd
bifurca y cae sus permisos, las capacidades se restablecen. No hay forma de evitar esto, y toda esa lógica de enlace en el núcleo es básica en torno a uid = 0, no a las capacidades. Esto significa que es poco probable que Capacidades sea la respuesta correcta a esta pregunta (al menos en el corto plazo). Por cierto,setcap
como otros han mencionado, no es una solución. No funcionó para mí, no funciona bien con los scripts, y estos se restablecen de todos modos cada vez que cambia el archivo.En mi exigua defensa, dije (en el comentario que eliminé ahora), que la sugerencia de iptables de James (que también menciona el OP) era la "segunda mejor solución". :-PAGS
>> TLDR <<
La solución es combinarla
systemd
coniptables
comandos sobre la marcha , como este ( tomado de DNSChain ):Aquí logramos lo siguiente:
iptables
systemd
limpia las reglas del firewall para nosotros, asegurándonos de eliminarlas cuando el demonio no se está ejecutando.systemd
afirma), supuestamente incluso si el demonio se ve comprometido y se estableceuid=0
.iptables
sigue siendo, desafortunadamente, una utilidad bastante fea y difícil de usar. Si el demonio está escuchando eneth0:0
lugar deeth0
, por ejemplo, los comandos son ligeramente diferentes .fuente
eth0:0
nunca más a menos que tengan una distribución de Linux realmente antigua . Han quedado en desuso durante años y eventualmente desaparecerán.# Generated by SolusVM
AmbientCapabilities=CAP_NET_BIND_SERVICE
funcionó perfectamente bien para mí en combinación conUser=
.systemd es un reemplazo de sysvinit que tiene la opción de lanzar un demonio con capacidades específicas. Opciones Capacidades =, CapabilityBoundingSet = en la página de manual systemd.exec (5) .
fuente
systemd
.La redirección de puertos tenía más sentido para nosotros, pero nos encontramos con un problema en el que nuestra aplicación resolvería una URL localmente que también necesitaba ser redirigida; (eso significa que eres shindig ).
Esto también le permitirá ser redirigido al acceder a la url en la máquina local.
fuente
Soportes modernos de Linux
/sbin/sysctl -w net.ipv4.ip_unprivileged_port_start=0
.fuente
Con systemd, solo necesita modificar ligeramente su servicio para aceptar sockets preactivados.
Más tarde puede usar systemd socket active .
No se necesitan capacidades, iptables u otros trucos.
Este es el contenido de los archivos systemd relevantes de este ejemplo de servidor http python simple
Expediente
httpd-true.service
Expediente
httpd-true.socket
fuente
Al inicio:
Luego puede unirse al puerto al que desea reenviar.
fuente
--to-port
existe?man iptables
solo menciona--to-ports
(plural).systemd
.Use la utilidad privbind : permite que una aplicación sin privilegios se una a puertos reservados.
fuente
También existe la 'forma djb'. Puede usar este método para iniciar su proceso como root que se ejecuta en cualquier puerto bajo tcpserver, luego le dará el control del proceso al usuario que especifique inmediatamente después de que comience el proceso.
Para obtener más información, consulte: http://thedjbway.b0llix.net/daemontools/uidgid.html
fuente
Dado que el OP es solo desarrollo / prueba, las soluciones menos que elegantes pueden ser útiles:
setcap se puede usar en el intérprete de un script para otorgar capacidades a los scripts. Si setcaps en el binario del intérprete global no es aceptable, haga una copia local del binario (cualquier usuario puede hacerlo) y obtenga root para setcap en esta copia. Python2 (al menos) funciona correctamente con una copia local del intérprete en su árbol de desarrollo de scripts. No se necesita suid para que el usuario root pueda controlar a qué capacidades tienen acceso los usuarios.
Si necesita realizar un seguimiento de las actualizaciones de todo el sistema para el intérprete, utilice un script de shell como el siguiente para ejecutar su script:
fuente
Probé el método de REDUCCIÓN DE PREROUTING de iptables. En núcleos anteriores parece que este tipo de regla no era compatible con IPv6 . Pero aparentemente ahora es compatible con ip6tables v1.4.18 y Linux kernel v3.8.
También descubrí que PREROUTING REDIRECT no funciona para conexiones iniciadas dentro de la máquina. Para trabajar para conexiones desde la máquina local, agregue también una regla de SALIDA - vea la redirección de puerto de iptables que no funciona para localhost . Por ejemplo, algo como:
También descubrí que PREROUTING REDIRECT también afecta los paquetes reenviados . Es decir, si la máquina también reenvía paquetes entre interfaces (por ejemplo, si actúa como un punto de acceso Wi-Fi conectado a una red Ethernet), entonces la regla de iptables también detectará las conexiones de los clientes conectados a los destinos de Internet y los redirigirá a la máquina. Eso no era lo que quería: solo quería redirigir las conexiones que se dirigían a la máquina misma. Descubrí que puedo hacer que solo afecte los paquetes dirigidos a la caja, agregando
-m addrtype --dst-type LOCAL
. Por ejemplo, algo como:Otra posibilidad es utilizar el reenvío de puertos TCP. Por ejemplo, usando
socat
:Sin embargo, una desventaja de ese método es que la aplicación que está escuchando en el puerto 8080 no conoce la dirección de origen de las conexiones entrantes (por ejemplo, para el registro u otros fines de identificación).
fuente
Respuesta en 2015 / septiembre:
ip6tables ahora es compatible con IPV6 NAT: http://www.netfilter.org/projects/iptables/files/changes-iptables-1.4.17.txt
Necesitarás el kernel 3.7+
Prueba:
fuente