Opções de repositórios PyPI privados e quais são as limitações de cada um

Os patches do php2shell (CVE-2026-109618 e CVE-2026-109619) para o PHP em fim de vida (EOL) já estão disponíveis. Como as respostas do atendimento de vendas estão mais demoradas do que o normal devido à alta demanda, a maneira mais rápida de obter os pacotes corrigidos é adquirir o ELS para Runtimes on-line (abre em uma nova aba). Leia as perguntas frequentes sobre os patches

Vá direto para um resumo gerado por IA desta postagem do blog

  • Resuma esta postagem com o Perplexity
  • Resuma esta postagem com o Gemini

Principais conclusões

  • Um repositório PyPI privado explica de onde vêm os pacotes, mas não se é seguro instalá-los.
  • Adicionar –extra-index-url em vez de definir –index-url para um único índice reabre a brecha que o repositório privado foi criado para fechar.
  • Um espelho ou cache disponibiliza tudo o que for publicado pelo servidor de origem, incluindo versões maliciosas.
  • Vincular um pacote instalável a uma fonte verificada requer uma etapa explícita de verificação, e não uma alteração na configuração.

Criar um repositório PyPI privado parece ser uma tarefa bem simples. Basta configurar o devpi ou o Artifactory, inserir a URL interna na documentação de integração e encerrar o ticket. Os desenvolvedores não vão mais baixar arquivos diretamente do PyPI público. O auditor recebe uma resposta. O pesadelo acaba.

Só que o repositório privado está apenas espelhando o PyPI público. A pergunta original agora tem uma resposta: o cache funciona, mas há um gargalo na política. No entanto, a questão de saber se um determinado pacote é confiável ainda não foi abordada. Ela foi transferida para outro lugar.

Essa é a parte que vale a pena analisar antes de escolher uma arquitetura. As quatro abordagens comuns para um repositório PyPI privado diferem enormemente no que verificam, e a verificação está ausente nos modelos básicos de espelho e proxy.

O que um repositório privado do PyPI realmente resolve

Quatro problemas, e eles são reais.

Disponibilidade, para que uma interrupção no PyPI público não afete suas implantações. Largura de banda e velocidade, pois baixar os mesmos pacotes mil vezes por dia da internet é um desperdício. Distribuição interna de pacotes, para que as bibliotecas privadas tenham um lugar para ficar além de uma URL do Git enterrada no arquivo requirements.txt. E uma ponto de controle de políticas, que é o que realmente importa para a segurança.

O que isso não resolve por si só é a integridade do pacote. Um cache do tipo “pull-through” busca os dados do servidor de origem, armazena o resultado e o fornece. Se o servidor de origem fornecer malware por três horas, o cache preserva esse malware fielmente e continua servindo-o a todos depois disso, com excelente latência.

Um repositório PyPI privado altera a origem dos seus pacotes. Ele não altera o que eles são. Tratar o próprio repositório como um controle de segurança é um erro arquitetônico comum nessa área.

A taxa de pacotes maliciosos que chegam aos registros públicos tem aumentado ano após ano, e um espelho que acompanha esse crescimento herda tudo isso por definição. Não há nada no mecanismo de espelhamento que filtre com base na intenção.

O erro com a URL fora do índice que estraga tudo

pip possui dois parâmetros que parecem intercambiáveis. Na verdade, não são, e é fácil não perceber a diferença — até o dia em que alguém explorar essa falha.

# Substitui o índice padrão. Apenas o seu repositório é consultado.
pip install –index-url https://pypi.internal.example.com/simple/ mypackage

# Adiciona um segundo índice. O pip pesquisa ambos, sem prioridade entre eles.
pip install –extra-index-url https://pypi.internal.example.com/simple/ mypackage

–extra-index-url geralmente aparece porque –index-url, por si só, causou algum problema inicialmente. Um pacote não foi encontrado, a compilação falhou e a adição de um segundo índice fez com que o erro desaparecesse.

Eis por que isso é importante. O pip não leva em conta de qual índice um pacote deve vir. Sua própria documentação é bem clara quanto a isso: não há prioridade entre os locais em que ele faz a busca; portanto, todos são verificados e a melhor correspondência para o requisito é escolhida, o que, na prática, significa a versão compatível mais recente. Se um invasor publicar a versão 99.0.0 do `internal-billing-utils` no PyPI público, o pip irá substituir sua versão interna 2.4.1 por ela sem hesitar.

Isso é confusão de dependências, e –extra-index-url é como ela ocorre.

Verifique como seus agentes de compilação estão realmente configurados, e não o que dizem os documentos. As variáveis PIP_INDEX_URL e PIP_EXTRA_INDEX_URL no ambiente substituem silenciosamente o arquivo pip.conf, e uma imagem base herdada de outra equipe é uma forma comum de isso passar despercebido.

python -m pip config debug
pip config get global.index-url

O comando `pip config debug` mostra de qual arquivo ou variável cada configuração se originou, o que geralmente é mais rápido do que ficar adivinhando. Aproveite para verificar o ambiente das duas variáveis do PIP enquanto estiver lá.

A solução é usar exclusivamente a opção –index-url e fazer com que seu repositório privado seja o único índice reconhecido pelo pip, com os pacotes internos e os do upstream sendo fornecidos por meio dele. A PEP 708 propôs metadados de repositório que permitiriam aos índices sinalizar essas relações e eliminar as suposições na fusão entre eles, mas, após três anos em status provisório, a proposta foi rejeitada em 2026 porque as implementações necessárias nunca foram concretizadas. A disciplina de índice único é o que realmente prevalece hoje.

Quatro maneiras de administrar um repositório PyPI privado

As opções se diferenciam pelo que fazem com os pacotes de origem, e não pelo nome do produto que consta na embalagem.

Abordagem Manuseio na fase inicial Verifica os artefatos Carga operacional
Espelho de corpo inteiro Copia todo o PyPI para o computador Não Elevado; o armazenamento cresce continuamente
Proxy pull-through Busca e armazena em cache sob demanda Não Baixo a moderado
Lista de permissões selecionada Somente pacotes aprovados são resolvidos Apenas o que foi verificado por uma pessoa Avaliação elevada e contínua
Registro gerenciado e verificado (por exemplo, SecureChain) Verifica e refaz antes de servir Sim Baixo, terceirizado

Espelhamento completo com bandersnatch é a resposta tradicional e, de longe, a que mais consome espaço de armazenamento. Todo o PyPI ocupa cerca de 44 TB de arquivos de lançamento até o momento da redação deste artigo, de acordo com página de estatísticas do PyPI, e esse número só cresce. O armazenamento é a parte fácil — manter a sincronização em dia com essa quantidade de dados é que representa o custo real.

Os proxies do tipo “pull-through” são a escolha mais comum. devpi, proxpi, Nexus Repository, Artifactory, AWS CodeArtifact, Azure Artifacts, Google Artifact Registry: produtos diferentes, mas com a mesma arquitetura subjacente. A função de proxy e cache resolve bem as questões de disponibilidade e armazenamento em cache, mas não faz nada para determinar se um artefato de origem é confiável, pois essa nunca foi sua função.

Listas de permissão selecionadas são um dos controles mais eficazes que uma equipe pode implementar internamente sem precisar criar um fluxo completo de verificação. Elas também são aquelas que falham discretamente, pois a fila de revisão acaba se tornando a tarefa menos apreciada por alguém e as aprovações passam a ser feitas em lotes para liberar um lançamento.

Os registros gerenciados e verificados são baseados na verificação, e não na disponibilidade. O SecureChain para Python funciona dessa maneira. Os pacotes são recompilados a partir do código-fonte e verificados antes mesmo de ficarem disponíveis para instalação, em vez de serem armazenados em cache posteriormente e verificados mais tarde.

Antes de escolher uma abordagem, execute o comando `pip download -r requirements.txt` e conte os pacotes distintos retornados, incluindo os transitivos. Dimensionando uma lista de permissões selecionada em relação às suas dependência direta pode subestimar gravemente a carga de revisão, pois é na árvore transitiva que reside o volume.

Espelhamento não é verificação

Há três questões distintas que uma configuração de empacotamento em Python pode responder, e é importante diferenciá-las, pois os produtos tendem a confundir esses conceitos.

Esse artefato chegou intacto? Os hashes respondem a essa pergunta, e o pip oferece um bom suporte para isso.

Este artefato é realmente de onde afirma ser? A proveniência e a assinatura respondem a essa pergunta, pelo menos em parte, quando as editoras se envolvem.

Esse artefato corresponde ao código-fonte a partir do qual alega ter sido compilado? Quase nada na cadeia de ferramentas padrão responde a essa pergunta.

A terceira pergunta é aquela que identifica rodas adulteradas. Uma wheel é um produto da compilação, e nada no sistema de pacotes exige que ela corresponda ao repositório ao qual o pacote está vinculado. O comprometimento da conta de um mantenedor pode resultar em um wheel cujo hash seja consistente, que seja instalado sem problemas e que contenha código que o repositório nunca tenha visto.

pip-compile –generate-hashes requirements.in
pip install –require-hashes -r requirements.txt

Ative o modo de verificação de hash, independentemente do que mais você fizer. Isso força todas as dependências, inclusive as transitivas, a serem fixadas com um hash, o que impede a substituição silenciosa e torna as instalações repetíveis. No entanto, isso não confirma se o artefato fixado já foi legítimo. Ele simplesmente mantém o que foi resolvido na primeira vez.

Resolver a terceira questão significa estabelecer uma ligação confiável entre o código-fonte e o artefato instalável, o que, na prática, significa recompilar a partir do código-fonte verificado em um ambiente controlado e instalar essa compilação, em vez de um binário opaco do desenvolvedor original. Trata-se de um trabalho de engenharia deliberado, não de uma configuração.

A Trusted Publishing e o que o durabletask revelou

Publicação Confiável substitui os tokens de API do PyPI de longa duração por credenciais de curta duração emitidas via OIDC para um fluxo de trabalho específico de CI. O token gerado expira em 15 minutos, portanto, não há credenciais de longa duração armazenadas em um repositório de segredos à espera de serem roubadas.

O SDK do durabletask da Microsoft não tinha essa função ativada quando a campanha TeamPCP distribuiu três versões maliciosas para o PyPI em 19 de maio de 2026. As versões 1.4.1 a 1.4.3 foram lançadas em um intervalo de 35 minutos, enviadas diretamente para o PyPI com um token de API de longa duração roubado que estava armazenado nos segredos do GitHub Actions do projeto. Sem tags correspondentes, sem execução do fluxo de trabalho de publicação, nada no histórico do repositório que explicasse como os lançamentos chegaram lá. É exatamente esse tipo de roubo de token que o Trusted Publishing existe para impedir.

Telnyx e LiteLLM já haviam aprendido essa lição cerca de oito semanas antes, da maneira mais difícil. Ambas tiveram versões maliciosas enviadas ao PyPI em março de 2026 sem tags correspondentes em seus repositórios e, posteriormente, passaram a utilizar a Publicação Confiável, conforme documentado no próprio relatório de incidentes do PyPI. O durabletask ainda não havia adotado essa medida quando a TeamPCP voltou à ativa em maio. Conforme sua versão mais recente até o momento da redação deste artigo, a 1.9.0 de 30 de julho de 2026, o PyPI ainda mostra os arquivos como publicados sem o Trusted Publishing.

Essa lacuna é a parte mais relevante da história, mais do que qualquer incidente isolado. A correção já existe há anos. Dois casos de violação de segurança de grande repercussão levaram dois projetos a adotá-la. Semanas depois, a mesma campanha comprometeu um terceiro projeto por meio de outra credencial de publicação roubada.

O Trusted Publishing é realmente eficaz contra o caminho do roubo de credenciais e apresenta duas limitações que vale a pena deixar bem claras. Ele protege os pacotes que você publica, não os que você utiliza; portanto, ativá-lo não tem efeito sobre as dependências que já estão presentes na sua árvore. Além disso, depende de que todos os mantenedores a montante de você façam a mesma escolha, o que não é algo com que se possa contar.

Controle Protege Não protege
Publicação confiável Pacotes que você publica Qualquer coisa que você instalar
Fixação de hash Contra a substituição após a primeira resolução Contra uma decisão inicial comprometida
Repositório privado Origem, disponibilidade e política dos pacotes controlados Integridade do artefato
Triagem no nível do registro Artefatos antes de serem resolvidos Código que você mesmo escreveu

Se sua organização publica pacotes, ative a Publicação Confiável ainda esta semana. Trata-se de uma pequena alteração na configuração que bloqueia uma rota de ataque inteira.

Reforço da segurança no lado do cliente

A arquitetura do repositório chama a atenção. A configuração do cliente é onde a aplicação das regras realmente ocorre, e geralmente é inconsistente.

Há quatro aspectos que vale a pena verificar em todos os ambientes onde o pip é executado. Primeiro, uma única URL de índice no arquivo pip.conf no nível do sistema, sem nenhuma URL de índice adicional em nenhum lugar. Segundo, as variáveis PIP_INDEX_URL e PIP_EXTRA_INDEX_URL devem estar desativadas nas imagens base e na configuração de CI. Terceiro, o modo de verificação de hash deve estar ativado na CI, mesmo que os desenvolvedores o ignorem localmente. Quarto, o tráfego de saída de rede dos agentes de compilação deve ser restrito para que um cliente mal configurado não consiga acessar o PyPI público de forma alguma.

É isso último que transforma a política em ação. Ocorre desvio de configuração, imagens base são herdadas e sempre há alguém que passa um sinalizador para desbloquear uma implantação. Uma política de saída que permita que os agentes de compilação acessem apenas o repositório privado aprovado detecta tudo isso sem depender da disciplina de ninguém. Bloquear um único nome de host não é suficiente, já que o índice e o host do arquivo para o qual ele aponta são separados.

Escolhendo uma abordagem

Adapte a abordagem ao que realmente precisa ser resolvido, e não ao que for mais rápido de implementar.

Um proxy pull-through é a escolha certa quando o objetivo é disponibilidade e armazenamento em cache. É uma boa infraestrutura, mas deixa de ser útil no momento em que passa a ser tratada como uma barreira de segurança. Uma lista de permissões cuidadosamente selecionada adiciona um ponto de controle de política que uma auditoria pode identificar, desde que alguém evite que a fila de revisão se transforme em um mero formalismo. O espelhamento completo raramente justifica seu custo de armazenamento fora de ambientes isolados fisicamente. Nenhuma das três opções garante, por si só, a integridade dos artefatos, e uma lista de permissões cuidadosamente selecionada oferece apenas a garantia que seu processo de revisão realmente estabelece.

Se a integridade dos artefatos estiver realmente dentro do escopo — e não apenas a disponibilidade ou uma trilha de auditoria —, o que você precisa é de uma camada de verificação que recompile os pacotes a partir de fontes confiáveis e os analise antes que sejam resolvidos. Um registro gerenciado e verificado oferece isso sem que você precise construir e operar o pipeline, o que, quando feito internamente, representa um compromisso de engenharia de vários trimestres, e não apenas um sprint.

Onde o SecureChain para Python se encaixa

Voltemos às três perguntas anteriores: “intacto”, “de onde afirma ser” e “corresponde à sua fonte”. A maioria das configurações de repositórios privados se limita à primeira. O SecureChain foi desenvolvido para responder a todas as três. Cada pacote é recompilado a partir do código-fonte em ambientes fortificados e submetido a uma triagem antes mesmo de ficar disponível para instalação, acompanhado de dados de proveniência SLSA Nível 3, SBOM e VEX, além de correções que continuam mesmo após a saída do mantenedor.

Se você quiser comparar isso com a sua própria árvore de dependências, pergunte aos nossos especialistas sobre o SecureChain para Python e a abordagem mais adequada para sua pilha de tecnologias.

Perguntas frequentes

O que é um repositório privado do PyPI?

Um índice de pacotes Python hospedado internamente que disponibiliza pacotes aos seus desenvolvedores e sistemas de compilação, em vez de direcioná-los diretamente ao PyPI público. Ele pode espelhar o repositório original, atuar como proxy e armazenar em cache sob demanda, disponibilizar apenas um conjunto aprovado ou filtrar os pacotes antes de disponibilizá-los.

Um repositório PyPI privado torna as instalações mais seguras?

Somente se verificar os pacotes. Um espelho ou cache pull-through fornece tudo o que o upstream publicou, incluindo versões maliciosas. O benefício de segurança decorre da triagem ou curadoria aplicada em uma camada superior, e não do próprio repositório.

Qual é a diferença entre “index-url” e “extra-index-url”?

–index-url substitui o índice padrão, de modo que apenas o seu repositório é consultado. –extra-index-url adiciona outro índice, e o pip pesquisa todos os índices configurados sem classificá-los; é assim que um pacote público malicioso pode ser resolvido e causar um ataque de confusão de dependências.

Como faço para evitar confusões com dependências no pip?

Utilize exclusivamente o –index-url, forneça pacotes internos e de upstream por meio desse único índice, remova a variável PIP_EXTRA_INDEX_URL em todos os locais e restrinja o tráfego de saída dos agentes de compilação, de modo que apenas o repositório aprovado seja acessível.

Devo hospedar um espelho completo do PyPI?

Raramente. Um espelhamento completo significa armazenar cerca de 44 TB, com esse volume aumentando constantemente, e não oferece nenhuma vantagem em termos de verificação em relação a um proxy de pull-through. O espelhamento completo faz mais sentido para ambientes isolados da rede (air-gapped).

O que é a Publicação Confiável no PyPI?

Um mecanismo de publicação baseado em OIDC que emite credenciais de curta duração para um fluxo de trabalho específico do CI, em vez de depender de tokens de API de longa duração. Ele protege os pacotes que você publica. Não tem efeito sobre os pacotes que você instala.

 

Resumo
Opções de repositórios PyPI privados e quais são as limitações de cada um
Nome do artigo
Opções de repositórios PyPI privados e quais são as limitações de cada um
Descrição
Um repositório PyPI privado controla a origem dos pacotes, e não se eles são seguros. Compare espelhos, proxies e registros com curadoria.
Autor
Nome da editora
TuxCare
Logotipo da editora

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.

Índice
Obtenha as respostas sobre segurança de código aberto de que você precisa

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.