Assinatura e integridade de software tratam de um problema operacional: como garantir que um artefato (binário, pacote, container, script, firmware, manifesto) que saiu do seu pipeline é exatamente o que chega ao ambiente de execução, e que qualquer pessoa (ou sistema) consiga verificar isso de forma automatizada. Na prática, o objetivo é reduzir riscos como: publicação acidental de build errado, substituição maliciosa no repositório, comprometimento de dependências, adulteração durante distribuição, e execução de código não aprovado em produção.
O que significa “integridade de software” no dia a dia
Integridade, aqui, é a propriedade de que o conteúdo não foi alterado desde um ponto de referência confiável. Esse ponto pode ser: o momento em que o artefato foi construído, o momento em que foi aprovado, ou o momento em que foi publicado. A integridade é verificada comparando um valor esperado (por exemplo, um digest) com o valor calculado do artefato recebido. Se houver qualquer alteração, a verificação falha.
Na prática, integridade de software quase nunca é “apenas um hash em um arquivo README”. O desafio real é: (1) como distribuir o valor esperado de forma confiável, (2) como associar esse valor a uma identidade e a um processo (quem assinou, com qual política, em qual pipeline), e (3) como automatizar a verificação em cada etapa (CI, registro de artefatos, CD, runtime).
O que significa “assinatura de software” e o que ela resolve
Assinar software significa produzir um objeto de assinatura associado ao artefato (ou ao seu digest) que pode ser verificado por terceiros usando uma chave pública confiável. Em termos operacionais, a assinatura resolve dois pontos que um hash sozinho não resolve: (1) autenticidade do emissor (você consegue vincular o artefato a um signatário), e (2) não repúdio operacional (você consegue auditar qual identidade/pipeline produziu e aprovou aquele artefato).
Em pipelines modernos, a assinatura costuma ser aplicada em um destes níveis:
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
- Assinatura do artefato final: binário, pacote, imagem de container, firmware, chart, etc.
- Assinatura de metadados: manifesto de release, SBOM, atestados de build/test, lista de arquivos e digests.
- Assinatura de tags/commits: garante integridade do histórico e do ponto de origem do código, mas não substitui assinatura do artefato construído.
Artefatos: o que assinar e por quê
Escolher “o que assinar” é uma decisão de engenharia. Assinar tudo pode ser caro e complexo; assinar pouco pode deixar lacunas. Um modelo prático é assinar o que é consumido por outro sistema automaticamente, e o que é executado em produção.
1) Pacotes e binários (deb/rpm, npm, pip, jars, executáveis)
Quando você distribui pacotes, o consumidor normalmente confia no repositório. A assinatura deve permitir que o consumidor valide o pacote mesmo se o repositório for comprometido. Isso inclui assinatura do pacote e/ou do índice do repositório (dependendo do ecossistema). Para binários distribuídos diretamente (downloads), assinar o arquivo e publicar a assinatura separadamente é comum, mas exige um canal confiável para obter a chave pública ou o certificado do signatário.
2) Imagens de container
Para containers, o ponto de consumo é o registry e o runtime (Kubernetes, por exemplo). A assinatura precisa se integrar ao fluxo de pull e admissão. Assinar a imagem por digest (não por tag) evita ambiguidades: tags podem ser movidas, digests não.
3) Infraestrutura como código e manifests
Manifests de deploy (YAML, Helm charts, Terraform plans) são alvos frequentes de adulteração porque controlam permissões, endpoints e imagens. Assinar manifests ou atestar que um conjunto de manifests foi gerado por um pipeline aprovado reduz risco de “mudança invisível” entre revisão e aplicação.
4) SBOM e atestados
SBOM (Software Bill of Materials) e atestados (proveniência, testes, SAST/DAST, aprovação) não são o software em si, mas são essenciais para decisões automatizadas (por exemplo, bloquear deploy se houver CVE crítico). Assinar esses documentos evita que alguém “limpe” o SBOM ou forje um atestado de teste.
Pipelines: onde a assinatura entra e quais são os pontos críticos
Um pipeline típico tem etapas: checkout do código, build, testes, empacotamento, publicação, deploy. A assinatura pode ocorrer em diferentes pontos, mas o local mais defensável é após o build e testes, quando o artefato final está pronto, e antes da publicação, para que o repositório/registry receba apenas artefatos assinados.
Pontos críticos que costumam quebrar a cadeia de confiança:
- Build não determinístico: o mesmo código gera artefatos diferentes (timestamps, ordem de arquivos, dependências baixadas sem pin). Isso dificulta auditoria e reproduções.
- Dependências não fixadas: baixar “latest” ou ranges amplos permite que o conteúdo mude sem alteração no repositório.
- Chaves de assinatura expostas no CI: armazenar chave privada como secret estático em variável de ambiente aumenta o impacto de um comprometimento do runner.
- Assinar tags em vez de digests: tags podem ser reatribuídas; a verificação precisa ser baseada em conteúdo imutável.
- Publicação antes da assinatura: se o artefato é publicado e depois assinado, existe uma janela em que consumidores podem baixar algo não assinado.
Verificação: quem verifica, quando verifica, e o que fazer quando falha
Verificação não é um evento único; é uma política aplicada em múltiplos pontos:
- No consumidor humano: alguém baixa um release e valida assinatura antes de executar.
- No consumidor automatizado: pipeline de deploy valida assinatura e atestados antes de promover para produção.
- No runtime: admission controller ou política de cluster bloqueia imagens não assinadas.
- No inventário: scanners e ferramentas de compliance verificam se o que está rodando corresponde ao que foi aprovado.
Quando a verificação falha, o comportamento deve ser previsível: bloquear execução/promoção, registrar evidências (hash observado, assinatura, identidade do signatário esperado), e acionar resposta (rollback, quarentena do artefato, investigação do pipeline/registry).
Passo a passo prático: assinatura e verificação de artefatos genéricos
O passo a passo abaixo é propositalmente genérico para caber em diferentes ferramentas. A ideia é separar: (1) cálculo de digest, (2) assinatura do digest, (3) distribuição de assinatura e chave pública, (4) verificação automatizada.
Passo 1: definir o artefato e o identificador imutável
Escolha o “objeto de verdade” que será verificado. Exemplos:
- Para arquivo: o próprio arquivo (binário, pacote, tarball).
- Para container: o digest da imagem (ex.: sha256:...).
- Para release composto: um manifesto com lista de arquivos e seus digests.
Evite identificar por nomes mutáveis (tags, “latest”, “release.zip” sem versão). Nome pode ser metadado; verificação deve usar conteúdo imutável.
Passo 2: gerar um manifesto de release (recomendado)
Em vez de assinar dezenas de arquivos individualmente, crie um manifesto que liste cada artefato e seu digest. Isso facilita auditoria e reduz pontos de falha.
# Exemplo de manifesto simples (formato ilustrativo, pode ser JSON/YAML/etc. conforme seu padrão interno)
release: 2026.01.12
artifacts:
- name: app-linux-amd64
sha256: <digest>
- name: app-windows-amd64.exe
sha256: <digest>
- name: sbom.json
sha256: <digest>Esse manifesto vira o “contrato” do release. Você assina o manifesto (ou assina cada digest e agrega), e consumidores verificam o manifesto antes de baixar/executar.
Passo 3: assinar no pipeline em ambiente controlado
Assine somente após testes e validações. O ideal é que a etapa de assinatura rode em um executor com controles mais fortes (isolamento, sem acesso amplo à internet, logs imutáveis, identidade de workload). Evite copiar a chave privada para múltiplos runners.
Boas práticas operacionais nessa etapa:
- Chave de assinatura com escopo: uma chave por produto/linha de negócio, e, se possível, por ambiente (release vs nightly).
- Política de aprovação: exigir aprovação humana ou regra de branch/tag para permitir assinatura de release.
- Registro de evidências: guardar metadados do build (commit, pipeline id, dependências, resultado de testes) como atestado assinado.
Passo 4: publicar artefatos e assinaturas juntos (ou com vínculo forte)
O consumidor precisa obter: (1) o artefato, (2) a assinatura, (3) a chave pública/cadeia de confiança do signatário. Publique assinatura e manifesto no mesmo release, mas não dependa apenas do mesmo canal para distribuir a chave pública. Para a chave pública, use um canal com governança (repositório de chaves corporativo, PKI interna, ou mecanismo de identidade de workload).
Passo 5: verificação automatizada no CD (gating)
Antes de promover para produção, o pipeline de deploy deve:
- Baixar o manifesto e a assinatura.
- Verificar a assinatura usando a chave pública confiável.
- Recalcular digests dos artefatos baixados e comparar com o manifesto.
- Validar políticas adicionais (por exemplo: “assinatura deve ser do pipeline de release”, “build deve ter passado testes X”, “SBOM deve existir”).
# Pseudofluxo de verificação (ilustrativo)
manifest = download("release-manifest")
sig = download("release-manifest.sig")
assert verify_signature(manifest, sig, trusted_public_key)
for artifact in manifest.artifacts:
file = download(artifact.name)
assert sha256(file) == artifact.sha256
assert policy_checks(manifest.metadata, attestations)O ponto importante é que a verificação deve falhar de forma “dura” (bloquear) quando não houver assinatura válida, e não apenas emitir warning.
Assinatura em ecossistemas específicos: padrões de uso e armadilhas
Assinatura de commits/tags vs assinatura de releases
Assinar commits/tags ajuda a garantir que o histórico não foi adulterado e que mudanças vieram de identidades autorizadas. Porém, isso não garante que o binário publicado foi construído a partir daquele commit, nem que o ambiente de build não foi comprometido. Por isso, trate assinatura de commits como um controle complementar, e mantenha assinatura do artefato e/ou atestados de proveniência como controle principal para distribuição e execução.
Repositórios de pacotes
Em muitos ecossistemas, a confiança recai sobre a assinatura do repositório (índices) e sobre o transporte seguro. O risco comum é “confiança transitiva” excessiva: se o repositório for comprometido, um atacante pode publicar uma versão maliciosa. Mitigações práticas incluem: pinning de versões, verificação de assinatura do pacote, e políticas de allowlist de publicadores.
Containers e políticas de admissão
Em ambientes orquestrados, a verificação deve acontecer antes do workload iniciar. Isso normalmente é feito com políticas de admissão que validam: (1) a imagem por digest, (2) a assinatura associada ao digest, (3) a identidade do signatário e (4) atestados (proveniência, testes, scanner). Armadilhas comuns:
- Permitir deploy por tag sem resolver para digest e fixar no manifesto.
- Assinar a imagem, mas não exigir verificação no cluster (controle existe, mas não é aplicado).
- Não separar chaves de assinatura de ambientes (dev assina algo que chega em prod).
Proveniência e atestados: integridade do “como foi feito”
Mesmo com assinatura do artefato, ainda existe a pergunta: “foi construído do jeito certo?”. Atestados assinados respondem isso. Exemplos de declarações úteis:
- Proveniência de build: commit/branch, repositório, parâmetros, identidade do runner, timestamps, digests de dependências.
- Resultados de testes: suíte executada, versão do framework, status, cobertura mínima.
- Varreduras: resultado de SCA/SAST/DAST, política aplicada, baseline.
- SBOM: lista de componentes e versões, com digest do documento.
O valor prático aparece quando você automatiza decisões: por exemplo, permitir deploy apenas se existir atestado de proveniência emitido por um builder aprovado e se o SBOM estiver presente e assinado.
Gestão operacional das chaves de assinatura no pipeline
O maior risco em assinatura de software é o vazamento ou uso indevido da chave de assinatura. Algumas práticas para reduzir esse risco:
- Separação de funções: quem aprova release não é necessariamente quem mantém a chave; o pipeline executa assinatura sob política.
- Chaves efêmeras ou identidade de workload: preferir modelos em que o pipeline obtém credenciais de assinatura de forma curta e auditável, em vez de armazenar chave estática.
- Escopo e rotação: chaves diferentes para produtos/ambientes; rotação planejada; capacidade de revogar rapidamente.
- Auditoria: registrar cada operação de assinatura com metadados (quem, quando, qual digest, qual pipeline).
- Proteção contra “re-sign” malicioso: impedir que um pipeline não autorizado assine artefatos; exigir políticas de branch/tag e aprovação.
Checklist prático: implementando assinatura e verificação sem travar o time
Checklist de desenho
- Definir quais artefatos são “executáveis” e exigem assinatura obrigatória.
- Definir o identificador imutável (digest) como referência em deploy.
- Definir onde a assinatura acontece (após testes, antes de publicar).
- Definir como a chave pública é distribuída e versionada.
- Definir política de verificação (onde bloquear e onde apenas alertar).
Checklist de pipeline
- Build gera artefato e manifesto com digests.
- Pipeline gera SBOM e atestados relevantes.
- Etapa de assinatura assina manifesto e atestados.
- Publicação inclui artefatos + manifesto + assinaturas.
- CD verifica assinatura e digests antes de promover.
Checklist de runtime (quando aplicável)
- Cluster/ambiente valida assinatura antes de executar (policy enforcement).
- Deploy usa digest fixo, não tag mutável.
- Logs de verificação e decisões ficam centralizados para auditoria.
Exemplo prático: fluxo de release com manifesto assinado e verificação em promoção
Imagine um serviço que publica: (1) uma imagem de container, (2) um chart/manifests, (3) um SBOM. Um fluxo robusto:
- Build: gera imagem e obtém seu digest; gera manifests apontando para o digest; gera SBOM.
- Manifesto de release: lista digest da imagem, digest do SBOM e digest do pacote de manifests.
- Assinatura: assina o manifesto e os atestados (proveniência e testes).
- Publicação: envia imagem ao registry e publica manifesto/assinaturas em repositório de releases.
- Promoção: pipeline de deploy baixa manifesto e assinaturas, verifica, e só então aplica manifests no cluster.
# Estrutura ilustrativa de manifesto para container + manifests + sbom
release: 2026.01.12
service: payments-api
artifacts:
- type: container-image
name: registry.example.com/payments-api
digest: sha256:<digest-da-imagem>
- type: manifests
name: payments-api-manifests.tgz
sha256: <digest-do-tar>
- type: sbom
name: sbom.spdx.json
sha256: <digest-do-sbom>
attestations:
- type: provenance
sha256: <digest-do-atestado>
- type: tests
sha256: <digest-do-atestado>Esse padrão facilita auditoria (“o que foi para produção?”), facilita rollback (manifesto anterior), e reduz risco de substituição silenciosa (qualquer alteração quebra a verificação).
Erros comuns e como evitá-los
“Assinamos, mas ninguém verifica”
Assinatura sem verificação obrigatória vira apenas documentação. Transforme verificação em gate no CD e, quando possível, em política no runtime.
“Verificamos por tag”
Tags são convenientes, mas não são imutáveis. Resolva tags para digests no momento de build e propague digests até produção.
“Chave privada no CI como secret estático”
Isso aumenta o impacto de um comprometimento do runner. Prefira mecanismos que reduzam exposição (assinatura em serviço dedicado, credenciais de curta duração, isolamento forte do job de assinatura).
“Assinamos o binário, mas o instalador baixa dependências sem verificação”
O instalador/launcher também precisa de integridade e deve verificar dependências (ou usar repositórios com verificação). Caso contrário, o atacante troca uma dependência e mantém o binário principal intacto.
“Assinamos o artefato, mas não assinamos metadados críticos”
Se políticas dependem de SBOM/atestados, esses documentos também precisam de integridade e autenticidade. Caso contrário, alguém pode forjar um SBOM “limpo” para permitir deploy.