Harbor 2.15.4: o patch que destrava o pipeline também muda seus defaults de segurança
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.