← todos os artigos

Harbor 2.15.4: o patch que destrava o pipeline também muda seus defaults de segurança

0

O webhook deixou de entregar. O job de assinatura começou a receber erro. A replicação pro ECR parou. Se isso apareceu depois de atualizar o Harbor, não trate os sintomas como incidentes independentes antes de olhar a versão.

O Harbor 2.15.3, publicado em 6 de outubro de 2026, trouxe correções de segurança com mudanças observáveis nos pipelines. O 2.15.4 saiu em 9 de outubro para resolver regressões e restaurar compatibilidade.

O detalhe: parte dessa compatibilidade vem de mudar defaults de proteção. Atualizar o binário e deixar o restante implícito pode produzir um resultado diferente do que você espera.

Esta é uma análise das releases e do código versionado. Não executei esses cenários em cluster; os trechos abaixo são referências de configuração.

Webhook interno: disponibilidade e SSRF na mesma decisão

A correção descrita no GHSA-2phj-cp9f-qq6w trata de SSRF: um administrador de projeto pode fazer o jobservice enviar requisições a destinos internos ou ao serviço de metadata da nuvem. O risco depende dos privilégios do usuário e do alcance de rede desse componente.

No 2.15.3, a defesa passou a bloquear destinos não públicos, inclusive nomes que resolvem para IPs privados. Isso afeta receptores legítimos dentro do Kubernetes, como um endpoint de CI em *.svc.cluster.local.

O PR que entrou no 2.15.4 restaura acesso a redes privadas por padrão. A configuração continua disponível: definir false ativa a guarda; variável ausente ou vazia permite o acesso.

Há uma exceção importante para quem já passou pelo 2.15.3: um harbor.yml migrado com allow_private_network_access: false explícito preserva esse valor. Instalação nova e instalação atualizada podem, portanto, ter comportamentos diferentes com a mesma versão.

Não conclua que o webhook necessariamente vai voltar só porque o patch foi aplicado. Confira a configuração efetiva.

Declare a decisão nos values

Se você quer manter a guarda contra destinos privados, o fragmento de harbor.yml é:

network:
  allow_private_network_access: false

Para instalações via Helm, as notas do 2.15.3 documentam a variável em core e jobservice. Para ativar a guarda, use:

core:
  extraEnvVars:
    - name: HARBOR_ALLOW_PRIVATE_NETWORK_ACCESS
      value: "false"

jobservice:
  extraEnvVars:
    - name: HARBOR_ALLOW_PRIVATE_NETWORK_ACCESS
      value: "false"

São fragmentos para incorporar aos seus values, preservando outras variáveis existentes. No instalador, reaplique pelo procedimento de prepare e reinício correspondente ao seu ambiente.

Se o receptor precisa continuar na rede privada, permitir o acesso exige um controle compensatório. O advisory recomenda restringir a saída do jobservice aos destinos necessários e bloquear metadata. Traduzindo para operação: inventarie receptores, revise quem pode administrá-los e desenhe o egress de acordo com a rede real.

Não vou colocar aqui uma NetworkPolicy genérica que promete cobrir qualquer CNI, DNS e topologia. O controle precisa funcionar onde o Harbor está instalado.

Assinar uma imagem exige ler o que ainda não está assinado

O outro ciclo quebrado é mais sutil. Num projeto com content trust habilitado, cosign e notation precisam ler o manifest para produzir a primeira assinatura. Mas a imagem ainda não assinada é justamente o que a política bloqueia.

Antes da correção do GHSA-wrw5-gmvj-gf23, um cliente com permissão de push e User-Agent de signer escapava tanto do controle de assinatura quanto da política de vulnerabilidades. O header é controlado pelo cliente: não é uma identidade confiável.

O 2.15.3 removeu a isenção geral e ofereceu uma exceção opt-in apenas para content trust. O 2.15.4 habilita essa exceção por padrão para preservar o fluxo de assinatura. Ela continua exigindo permissão de push; não dá a uma conta com apenas pull o mesmo privilégio. A política de vulnerabilidades não é dispensada por essa exceção.

Esse limite importa. “O signer voltou” não significa “todas as políticas foram desativadas”. Também não significa que o content trust seja uma barreira absoluta para toda conta que consegue publicar.

Como exigir assinatura sem a exceção legada

Para desabilitar o bootstrap legado, o template do instalador na tag 2.15.4 oferece:

content_trust:
  legacy_signer_pull_enabled: false

No Helm, configure em core:

core:
  extraEnvVars:
    - name: CONTENT_TRUST_LEGACY_SIGNER_PULL_ENABLED
      value: "false"

Se juntar esse trecho com o exemplo anterior, use uma única seção core e inclua ambas as variáveis na mesma lista.

A consequência precisa entrar no desenho do pipeline: assinar uma imagem nova dentro do projeto que já exige assinatura pode falhar. O PR do instalador também explica por que editar manualmente common/config/core/env não é uma solução durável: o arquivo é gerado novamente por prepare.

Minha recomendação operacional é separar contas de publicação das credenciais usadas pelo runtime. O advisory recomenda contas de deploy com permissão apenas de pull. Se a exceção permanecer habilitada para viabilizar assinatura, registre quais contas de push são confiáveis e valide a política com uma conta real de deploy, não com o robot do CI.

E a replicação pro ECR?

As notas do 2.15.3 registram uma regressão na validação do header Location de uploads: o endpoint configurado do adapter ECR difere do host usado efetivamente para os dados.

O backport incluído no 2.15.4 passa a considerar a origem da requisição efetiva na validação do destino de upload. Essa correção não é um motivo para desligar globalmente controles de webhook ou content trust: são caminhos distintos.

Para quem depende de replicação, inclua um envio real ao destino no plano de validação. A existência do patch é evidência da correção no projeto; a execução bem-sucedida no seu registry ainda precisa ser observada.

O que fazer a seguir

Se você está avaliando a linha 2.15, prefira planejar a atualização com as correções do 2.15.4 em vez de parar no 2.15.3 e improvisar exceções durante o incidente.

Antes da janela, registre os dois valores: acesso a redes privadas e bootstrap de signer. Depois, valide entrega dos webhooks esperados, assinatura de uma imagem nova, bloqueio de pull com a conta de deploy e replicação quando usada.

O resultado esperado não é apenas “pipeline verde”. É pipeline funcionando com os limites de rede e de confiança que você escolheu — e consegue explicar.