É muito chato ter essa limitação na minha caixa de desenvolvimento, quando nunca haverá usuários além de mim.
Estou ciente das soluções padrão , mas nenhuma delas faz exatamente o que eu quero:
- authbind (A versão no teste Debian, 1.0, suporta apenas IPv4)
- Usando o destino REDIRECT do iptables para redirecionar uma porta baixa para uma porta alta (a tabela "nat" ainda não foi implementada para ip6tables, a versão IPv6 do iptables)
- sudo (Correr como root é o que estou tentando evitar)
- SELinux (ou similar). (Esta é apenas a minha caixa de desenvolvimento, não quero apresentar muita complexidade extra.)
Existe alguma sysctl
variável simples para permitir que processos não raiz se liguem a portas "privilegiadas" (portas menores que 1024) no Linux, ou estou sem sorte?
Edição: Em alguns casos, você pode usar os recursos para fazer isso.
Respostas:
Ok, obrigado às pessoas que apontaram o sistema de
CAP_NET_BIND_SERVICE
recursos e recursos. Se você possui um kernel recente, é realmente possível usá-lo para iniciar um serviço como não raiz, mas vincular portas baixas. A resposta curta é que você faz:E, a qualquer momento, a
program
partir de então, ele terá aCAP_NET_BIND_SERVICE
capacidade.setcap
está no pacote debianlibcap2-bin
.Agora, para as advertências:
program
que tenha privilégios elevados, comosetcap
ousuid
. Portanto, se vocêprogram
usa seus próprios.../lib/
, talvez seja necessário procurar outra opção, como encaminhamento de porta.Recursos:
setcap
.Nota: O RHEL adicionou isso pela primeira vez na v6 .
fonte
/usr/bin/java
e, em seguida, abriria a capacidade para qualquer aplicativo java em execução no sistema. Recursos muito ruins também não podem ser definidos por usuário./etc/security/capability.conf
alguma ajuda no Debian / Ubuntu?Você pode fazer um redirecionamento de porta. É o que faço para um servidor de políticas do Silverlight em execução em uma caixa Linux
fonte
/etc/network/if-up.d/firewall
.A maneira padrão é torná-los "setuid" para que eles sejam inicializados como root e descartam esse privilégio root assim que se conectam à porta, mas antes de começarem a aceitar conexões com ela. Você pode ver bons exemplos disso no código fonte do Apache e INN. Disseram-me que o Lighttpd é outro bom exemplo.
Outro exemplo é o Postfix, que usa vários daemons que se comunicam por meio de pipes, e apenas um ou dois deles (que fazem muito pouco, exceto aceitam ou emitem bytes) são executados como root e o restante é executado com um privilégio mais baixo.
fonte
binfmt_misc
e sua bandeira 'C', eu não tenho certeza sobre os outros.)Ou faça um patch do seu kernel e remova a verificação.
(Opção de último recurso, não recomendada).
Em
net/ipv4/af_inet.c
, remova as duas linhas que lêeme o kernel não verifica mais portas privilegiadas.
fonte
Você pode configurar um túnel SSH local, por exemplo, se você deseja que a porta 80 atinja seu aplicativo vinculado a 3000:
Isso tem a vantagem de trabalhar com servidores de script e ser muito simples.
fonte
sudo nc -l 80 | nc localhost 3000
Atualização 2017:
Use authbind
Muito melhor do que CAP_NET_BIND_SERVICE ou um kernel personalizado.
O Authbind concede confiança ao usuário / grupo e fornece controle sobre o acesso por porta e suporta IPv4 e IPv6 (o suporte ao IPv6 foi adicionado recentemente).
Instalar:
apt-get install authbind
Configure o acesso às portas relevantes, por exemplo, 80 e 443 para todos os usuários e grupos:
Execute seu comando via
authbind
(opcionalmente especificando
--deep
ou outros argumentos, consulte a página do manual):por exemplo
Como acompanhamento da fabulosa recomendação de Joshua (= não recomendada, a menos que você saiba o que faz) para hackear o kernel:
Eu publiquei aqui primeiro .
Simples. Com um kernel normal ou antigo, você não.
Como apontado por outros, o iptables pode encaminhar uma porta.
Como também apontado por outros, CAP_NET_BIND_SERVICE também pode fazer o trabalho.
É claro que CAP_NET_BIND_SERVICE falhará se você iniciar seu programa a partir de um script, a menos que defina o limite no interpretador de shell, o que é inútil, você poderá executar o serviço como root ...
por exemplo, para Java, você deve aplicá-lo para a JVM JAVA
Obviamente, isso significa que qualquer programa Java pode ligar portas do sistema.
Dito para mono / .NET.
Também tenho certeza de que o xinetd não é a melhor das idéias.
Mas como os dois métodos são hacks, por que não apenas elevar o limite, elevando a restrição?
Ninguém disse que você precisa rodar um kernel normal, então você pode rodar o seu próprio.
Você acabou de baixar a fonte para o kernel mais recente (ou o mesmo que você possui atualmente). Depois, você vai para:
Lá você procura esta linha
e mude para
se você não quiser ter uma situação ssh insegura, altere-a para o seguinte: #define PROT_SOCK 24
Geralmente, eu usaria a configuração mais baixa que você precisa, por exemplo, 79 para http ou 24 ao usar SMTP na porta 25.
Isso já é tudo.
Compile o kernel e instale-o.
Reinicie.
Concluído - esse limite estúpido é GONE e também funciona para scripts.
Aqui está como você compila um kernel:
https://help.ubuntu.com/community/Kernel/Compile
Em poucas palavras, use o iptables se quiser permanecer seguro, compile o kernel se quiser ter certeza de que essa restrição nunca mais o incomoda.
fonte
Os recursos de arquivo não são ideais, pois podem ser interrompidos após uma atualização do pacote.
A solução ideal, IMHO, deve ser a capacidade de criar um shell com um
CAP_NET_BIND_SERVICE
conjunto herdável .Aqui está uma maneira um tanto complicada de fazer isso:
capsh
O utilitário pode ser encontrado no pacote libcap2-bin nas distribuições Debian / Ubuntu. Aqui está o que se passa:sg
altera o ID do grupo efetivo para o do usuário daemon. Isso é necessário porquecapsh
deixa o GID inalterado e, definitivamente, não o queremos.$DAEMONUSER
--keep=1
), exceto herdáveiscap_net_bind_service
O resultado é um processo com usuário e grupo especificados e
cap_net_bind_service
privilégios.Como exemplo, uma linha do
ejabberd
script de inicialização:fonte
capsh
fazer nada além de "não é possível executar o arquivo binário" ao usar as opções--
ou==
. Eu me pergunto o que estou perdendo.--
é passado para/bin/bash
, então você pode tentar-c 'your command'
. Infelizmente, parece que estou enfrentando o mesmo problema que o @Cyberax, porque recebo "permissão negada" ao tentarbind
.--gid
em vez desg
(ou--user
quais conjuntos--uid
,--gid
e--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 algum motivo, ninguém menciona sobre a redução do sysctl net.ipv4.ip_unprivileged_port_start para o valor necessário. Exemplo: precisamos vincular nosso aplicativo à porta 443.
Alguns podem dizer que há um problema de segurança em potencial: usuários sem privilégios agora podem se conectar a outras portas privilegiadas (444-1024). Mas você pode resolver esse problema facilmente com o iptables, bloqueando outras portas:
Comparação com outros métodos. Este método:
Dependendo da situação, eu escolheria entre sysctl, CAP, authbind e iptables-redirect. E isso é ótimo, pois temos tantas opções.
fonte
Duas outras possibilidades simples:
Existe uma solução antiga (fora de moda) para "um daemon que se liga a uma porta baixa e controla o seu daemon". É chamado inetd (ou xinetd). Os contras são:
Prós:
Outra alternativa: um proxy hackeado (netcat ou até algo mais robusto ) da porta privilegiada para alguma porta arbitrária e de numeração alta, na qual você pode executar o daemon de destino. (O Netcat obviamente não é uma solução de produção, mas "apenas minha caixa de desenvolvimento", certo?). Dessa forma, você poderia continuar usando uma versão do servidor compatível com a rede, precisaria apenas do root / sudo para iniciar o proxy (na inicialização), não dependeria de recursos complexos / potencialmente frágeis.
fonte
Minha "solução padrão" usa socat como o redirecionador de espaço do usuário:
Cuidado para não escalar, bifurcar é caro, mas é assim que o socat funciona.
fonte
O Linux suporta recursos para suportar permissões mais refinadas do que apenas "este aplicativo é executado como raiz". Um desses recursos é
CAP_NET_BIND_SERVICE
sobre a ligação a uma porta privilegiada (<1024).Infelizmente, não sei como explorar isso para executar um aplicativo como não raiz e ainda o fornecer
CAP_NET_BIND_SERVICE
(provavelmente usandosetcap
, mas é provável que exista uma solução existente para isso).fonte
Eu sei que essa é uma pergunta antiga, mas agora com os kernels recentes (> = 4.3), finalmente há uma boa resposta para isso - os recursos do ambiente.
A resposta rápida é pegar uma cópia da versão mais recente (ainda não lançada) do libcap do git e compilá-la. Copie o
progs/capsh
binário resultante em algum lugar (/usr/local/bin
é uma boa escolha). Então, como root, inicie seu programa comEm ordem, estamos
cap_net_bind_service
capacidade aos conjuntos herdados e ambientaisbash -c 'your-command'
(desde quecapsh
inicia automaticamente o bash com os argumentos seguintes--
)Há muita coisa acontecendo sob o capô aqui.
Em primeiro lugar, estamos rodando como root; portanto, por padrão, temos um conjunto completo de recursos. Incluído nisso está a capacidade de alternar uid & gid com os syscalls
setuid
esetgid
. No entanto, normalmente quando um programa faz isso, ele perde seu conjunto de recursos - é para que a maneira antiga de eliminar raizsetuid
ainda funcione. O--keep=1
sinalizador informacapsh
para emitir oprctl(PR_SET_KEEPCAPS)
syscall, que desativa a queda de recursos ao alterar o usuário. A mudança real dos usuárioscapsh
acontece com a--user
bandeira, que é executadasetuid
esetgid
.O próximo problema que precisamos resolver é como definir as capacidades de uma maneira que continue depois que nós,
exec
nossos filhos. O sistema de recursos sempre teve um conjunto de recursos 'herdado', que é "um conjunto de recursos preservados em um execve (2)" [ recursos (7) ]. Embora isso pareça resolver nosso problema (apenas defina acap_net_bind_service
capacidade como herdada, certo?), Na verdade, isso só se aplica a processos privilegiados - e nosso processo não é mais privilegiado, porque já mudamos de usuário (com o--user
sinalizador).O novo conjunto de recursos ambientais soluciona esse problema - é "um conjunto de recursos preservados em uma execve (2) de um programa que não é privilegiado". Ao colocar
cap_net_bind_service
o ambiente definido, quando ocapsh
exec for nosso programa de servidor, nosso programa herdará esse recurso e poderá vincular ouvintes a portas baixas.Se você estiver interessado em saber mais, a página do manual de recursos explica isso em detalhes. Correndo
capsh
atravésstrace
também é muito informativo!fonte
--addamb
bandeira foi introduzida com a libcap 2.26. Meu sistema tinha 2,25 e eu tive que construir a partir da fonte.TLDR: para "a resposta" (como eu a vejo), vá para a parte >> TLDR << nesta resposta.
OK, eu descobri (desta vez de verdade), a resposta a esta pergunta, e essa minha resposta também é uma maneira de me desculpar por promover outra resposta (aqui e no twitter) que eu pensei que era "a melhor ", mas depois de tentar, descobri que eu estava enganado sobre isso. Aprenda com meus erros, crianças: não promova algo até que você realmente tente!
Mais uma vez, revi todas as respostas aqui. Eu tentei alguns deles (e optei por não tentar outros porque simplesmente não gostei das soluções). Eu pensei que a solução era usar
systemd
com seusCapabilities=
eCapabilitiesBindingSet=
configurações. Depois de lutar com isso por algum tempo, descobri que essa não é a solução porque:Os recursos destinam-se a restringir os processos raiz!
Como o OP afirmou sabiamente, é sempre melhor evitar isso (para todos os seus daemons, se possível!).
Você não pode usar as opções relacionadas aos Recursos com
User=
eGroup=
nossystemd
arquivos da unidade, porque os recursos SEMPRE são redefinidos quandoexecev
(ou seja qual for a função) é chamada. Em outras palavras, quandosystemd
bifurca e diminui suas permissões, os recursos são redefinidos. Não há como contornar isso, e toda essa lógica de ligação no kernel é básica em torno de uid = 0, não de recursos. Isso significa que é improvável que os Recursos sejam a resposta certa para essa pergunta (pelo menos em breve). Aliás,setcap
como outros já mencionaram, não é uma solução. Não funcionou para mim, não funciona muito bem com scripts, e eles são redefinidos de qualquer maneira sempre que o arquivo é alterado.Na minha escassa defesa, afirmei (no comentário que apaguei agora), que a sugestão de iptables de James (que o OP também menciona) era a "segunda melhor solução". :-P
>> TLDR <<
A solução é combinar
systemd
comiptables
comandos on-the-fly , como este ( extraído do DNSChain ):Aqui realizamos o seguinte:
iptables
systemd
limpa as regras de firewall para nós, removendo-as quando o daemon não está em execução.systemd
afirma), supostamente mesmo se o daemon estiver comprometido e configuradouid=0
.iptables
ainda é, infelizmente, um utilitário feio e difícil de usar. Se o daemon estiver ouvindo emeth0:0
vez deeth0
, por exemplo, os comandos serão ligeiramente diferentes .fonte
eth0:0
mais, a menos que eles tenham uma distribuição Linux realmente antiga . Eles estão obsoletos há anos e acabarão desaparecendo.# Generated by SolusVM
AmbientCapabilities=CAP_NET_BIND_SERVICE
funcionou perfeitamente bem para mim em combinação comUser=
.systemd é um substituto sysvinit que tem uma opção para iniciar um daemon com recursos específicos. Opções Capabilities =, CapabilityBoundingSet = na página de manual systemd.exec (5) .
fonte
systemd
.O redirecionamento de porta fazia mais sentido para nós, mas encontramos um problema em que nosso aplicativo resolveria um URL localmente que também precisava ser redirecionado; (isso significa que você brinca ).
Isso também permitirá que você seja redirecionado ao acessar o URL na máquina local.
fonte
Suporte moderno ao Linux
/sbin/sysctl -w net.ipv4.ip_unprivileged_port_start=0
.fonte
Com o systemd, você só precisa modificar levemente seu serviço para aceitar soquetes pré-ativados.
Posteriormente, você pode usar o systemd socket ativar .
Não são necessários recursos, iptables ou outros truques.
Este é o conteúdo dos arquivos systemd relevantes deste exemplo de servidor http python simples
Arquivo
httpd-true.service
Arquivo
httpd-true.socket
fonte
Na inicialização:
Em seguida, você pode vincular à porta para a qual encaminhar.
fonte
--to-port
existe?man iptables
apenas menciona--to-ports
(plural).systemd
.Use o utilitário privbind : ele permite que um aplicativo sem privilégios se ligue a portas reservadas.
fonte
Há também o 'caminho djb'. Você pode usar esse método para iniciar seu processo como root em execução em qualquer porta em tcpserver; depois, ele entregará o controle do processo ao usuário especificado imediatamente após o início do processo.
Para obter mais informações, consulte: http://thedjbway.b0llix.net/daemontools/uidgid.html
fonte
Como o OP é apenas desenvolvimento / teste, soluções menos sofisticadas podem ser úteis:
O setcap pode ser usado no intérprete de um script para conceder recursos aos scripts. Se setcaps no binário global do intérprete não for aceitável, faça uma cópia local do binário (qualquer usuário pode) e instale o root no setcap nesta cópia. Python2 (pelo menos) funciona corretamente com uma cópia local do intérprete na sua árvore de desenvolvimento de scripts. Nenhum suid é necessário para que o usuário root possa controlar quais recursos os usuários têm acesso.
Se você precisar rastrear atualizações de todo o sistema para o intérprete, use um shell script como o seguinte para executar seu script:
fonte
Eu tentei o método iptables PREROUTING REDIRECT. Em kernels antigos, parece que esse tipo de regra não é suportado no IPv6 . Mas, aparentemente, agora é suportado no ip6tables v1.4.18 e no kernel do Linux v3.8.
Também descobri que PREROUTING REDIRECT não funciona para conexões iniciadas dentro da máquina. Para trabalhar com conexões da máquina local, adicione também uma regra de SAÍDA - consulte o redirecionamento de porta iptables não funcionando para o host local . Por exemplo, algo como:
Também descobri que PREROUTING REDIRECT também afeta pacotes encaminhados . Ou seja, se a máquina também estiver encaminhando pacotes entre interfaces (por exemplo, se estiver atuando como um ponto de acesso Wi-Fi conectado a uma rede Ethernet), a regra iptables também capturará as conexões dos clientes conectados aos destinos da Internet e as redirecionará para a máquina. Não era isso que eu queria; eu só queria redirecionar as conexões direcionadas à própria máquina. Descobri que posso afetar apenas pacotes endereçados à caixa, adicionando
-m addrtype --dst-type LOCAL
. Por exemplo, algo como:Uma outra possibilidade é usar o encaminhamento de porta TCP. Por exemplo, usando
socat
:No entanto, uma desvantagem desse método é que o aplicativo que está atendendo na porta 8080 não conhece o endereço de origem das conexões de entrada (por exemplo, para log ou outros fins de identificação).
fonte
Resposta em 2015 / Sep:
O ip6tables agora suporta NAT do IPV6: http://www.netfilter.org/projects/iptables/files/changes-iptables-1.4.17.txt
Você precisará do kernel 3.7+
Prova:
fonte