Cilium opera no caminho de rede em nível de kernel de milhões de pods Kubernetes: de provedores de nuvem a clusters próprios de bancos e empresas de telecomunicações. Se alguém comprometesse o pipeline de construção do Cilium, a área de impacto seria comparável ao incidente da SolarWinds, mas no ecossistema nativo da nuvem. Portanto, a abordagem do projeto à segurança de CI/CD é interessante não apenas para os mantenedores de outros projetos de código aberto: os mesmos padrões são úteis para qualquer equipe que construa artefatos de produção no GitHub Actions. A equipe VK Cloud traduziu o artigo com configurações YAML específicas, decisões de design e uma lista honesta do que o Cilium ainda não fez.
Introdução
Os últimos doze meses foram difíceis para a cadeia de suprimentos de código aberto. O Axios foi comprometido no npm – um Trojan de acesso remoto (RAT) foi entregue dentro de versões de aparência normal. O pacote PyPI LiteLLM foi sequestrado para roubar variáveis de ambiente. Forks de typosquatting do Trivy foram publicados – contando com aqueles que cometem erros de digitação ao digitar go install. E o exemplo canônico – o hack da SolarWinds de 2020 – continua sendo uma história instrutiva à qual todos retornam: os invasores invadiram o sistema de construção e distribuíram malware por meio de atualizações regulares do Orion para cerca de 18.000 organizações, incluindo agências federais dos EUA, OTAN e Microsoft. O malware ficou inativo por meses. O hack passou despercebido durante a maior parte do ano.
Cilium opera no caminho de rede em nível de kernel de milhões de pods Kubernetes. Se nossa cadeia de suprimentos fosse comprometida, a área de impacto seria considerável. Fortalecer a proteção contra tal cenário é um trabalho constante, e queremos registrar em detalhes o que exatamente fazemos. A maior parte do que é descrito não está vinculada ao Cilium: qualquer projeto de código aberto que execute CI/CD no GitHub Actions pode aplicar esses padrões. Também observamos lugares onde ainda não estamos à altura – talvez algo sirva como um ponto de partida útil para outros.
Em resumo: níveis de proteção de pipeline
Se não houver tempo para ler tudo, aqui está o que o Cilium está fazendo para fortalecer a cadeia de suprimentos hoje, por níveis de pipeline:
| Nível | Controle | O que faz | Quem executa as compilações |
|---|---|---|---|
| Quem executa as compilações | Controle de gatilhos via Ariane | Somente membros verificados da organização podem executar o CI-workflow a partir de comentários em PRs, de acordo com uma lista explícita de workflows permitidos. | Controle de gatilhos via Ariane |
| Qual código o CI executa | Checkouts de duas fases para pull_request_target | Código confiável (composite actions, scripts, lógica de assinatura) é carregado da branch base. O head PR é usado apenas como contexto de construção do Docker e nunca é executado como um script. | Checkouts de duas fases para pull_request_target |
| Quem revisa as mudanças do CI | Gate CODEOWNERS | Tudo em .github/ requer revisão da equipe de CI responsável pela segurança, e auto-approve.yaml requer um mantenedor. | Gate CODEOWNERS |
| Quais dependências o CI puxa | Ações e imagens fixadas por SHA | Cada referência uses: aponta para o SHA de 40 caracteres do commit. As imagens de contêiner são fixadas por @sha256: digest. O Renovate mantém os pins atualizados e espera alguns dias antes de capturar novas versões. | Ações e imagens fixadas por SHA |
| Quais módulos Go entram no binário | Dependências Go vendored | Tudo é commitado em vendor/ e revisado pela equipe @cilium/vendor, então um módulo de typosquatting ou sequestrado aparece como um diff durante a revisão. | Dependências Go vendored |
| Como os workflows podem parecer | Análise estática de workflow | CodeQL requer a especificação obrigatória de permissions: em cada workflow, actionlint detecta padrões inseguros, e ambos marcam a injeção de expressões do GitHub Actions em blocos run:. | Análise estática de workflow |
| Quais credenciais estão disponíveis | Isolamento de credenciais de CI e produção | As credenciais de CI só podem enviar para tags de desenvolvimento *-ci. As credenciais do registro de produção estão atrás de um ambiente protegido release, que requer aprovação do mantenedor. | Isolamento de credenciais de CI e produção |
| O que os consumidores podem verificar | Versões assinadas | Cada imagem de lançamento e gráfico Helm é assinado pelo Sigstore Cosign via OIDC sem chave, com atestações SBOM (Software Bill of Materials, especificação da composição do software) anexadas. | Versões assinadas |
| Onde ainda não estamos à altura | Lacunas que estamos fechando | Sem proveniência SLSA, sem revisão de dependências durante o PR, sem govulncheck no CI e vários links internos @main que precisam ser movidos para um repositório de composite actions dedicado. | Lacunas que estamos fechando |
A seguir, cada linha é analisada em mais detalhes – com decisões de design e o que decidimos intencionalmente não fazer (por exemplo, fazer fork de cada ação de terceiros para nossa organização).
Quem e o que pode ser executado no CI
A primeira pergunta em qualquer história sobre a cadeia de suprimentos de CI é: quem pode executar uma compilação e qual código ela executa? Muitas violações de CI começam aqui – enganando o sistema para executar código controlado pelo invasor com privilégios elevados.
Restringindo gatilhos de workflow via Ariane
Ariane é um bot do GitHub, escrito internamente por nós, para executar (dispatch) CI-workflows a partir de comentários em PRs. Quando um mantenedor escreve /test ou /ci-eks em um pull request, Ariane verifica se o comentarista é membro da equipe organization-members, determina quais workflows executar (incluindo dependências – por exemplo, testes que primeiro precisam de uma nova compilação de imagem) e os executa via workflow_dispatch.
A parte interessante é a allow-list (lista de permissões). Somente membros verificados da organização podem executar o workflow, e o conjunto de workflows disponíveis está listado manualmente na configuração:
yaml# .github/ariane-config.yaml allowed-teams: - organization-members triggers: /test\s*: workflows: - conformance-aws-cni.yaml - conformance-clustermesh.yaml - conformance-eks.yaml # ...and so on depends-on: - /build-images-dependency /ci-aks: workflows: - conformance-aks.yaml depends-on: - /build-images-dependency
Um comentarista externo aleatório com /test em um PR será ignorado. Ele não executará conjuntos de conformidade caros de provedores de nuvem e não desperdiçará nossos minutos de CI.
Separando código confiável e não confiável no CI
Quando alguém abre um PR, precisamos construir seu código, mas não podemos confiar nele. Este é o problema clássico de pull_request_target. Evitamos pull_request_target sempre que possível, mas alguns workflows ainda precisam dele – e os envolvemos com medidas de proteção.
O workflow de construção de imagem é um exemplo canônico. Ele divide o checkout em dois:
yaml# .github/workflows/build-images-ci.yaml - name: Checkout base or default branch (trusted) uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.base_ref || github.event.repository.default_branch }} persist-credentials: false # ...trusted setup steps run here, including loading composite actions... # Warning: since this is a privileged workflow, subsequent workflow job # steps must take care not to execute untrusted code. - name: Checkout pull request branch (NOT TRUSTED) uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false ref: ${{ steps.tag.outputs.sha }}
O primeiro checkout pega a branch base – código que já foi revisado e mesclado – para que possamos carregar composite actions, scripts e lógica de assinatura Cosign de uma fonte verificada. E somente depois disso o workflow executa o checkout do head PR – e este checkout é usado puramente como um contexto de construção para docker build. Nada da branch PR é executado como um script.
Relatórios de segurança sobre este padrão chegam regularmente. Scanners automatizados e pesquisadores bem-intencionados veem "pull_request_target mais um segundo checkout" e marcam isso como uma vulnerabilidade. Em um caso típico, eles estão certos. No nosso – o workflow é projetado intencionalmente para que o padrão permaneça seguro:
- Nenhum passo
run:executa scripts do checkout não confiável. Cada bloco shell após o segundo checkout é escrito embutido no workflow YAML (verificações de uso de disco, cópia de arquivos, saída de digest). Nada é conectado da branch PR. - Nenhuma
composite actionstambém é carregada do checkout não confiável. Todas ascomposite actions(set-runtime-image, cosign, set-env-variables) vêm do checkout confiável da branch base ou de um diretório salvo../cilium-base-branch/. Também estamos trabalhando para mover essascomposite actionspara um repositório dedicado, para que não seja necessário fazer checkout do código-fonte para executá-las. - O Docker BuildKit realmente executa o Dockerfile não confiável – esse é o objetivo de construir uma imagem de CI a partir de um PR. O BuildKit funciona isoladamente: sem variáveis de ambiente do GitHub Actions, sem segredos do repositório, sem acesso ao armazenamento de credenciais do Docker do executor. Não há segredos nos argumentos de construção que passamos – apenas um link para a imagem de tempo de execução e o nome da variante do operador.
- Dados não confiáveis vão para exatamente uma ação confiável. O arquivo
runtime-image*.txtdo PR é alimentado na ação confiável set-runtime-image, que verifica se o link para a imagem começa comquay.io/cilium/e remove as quebras de linha – para que um invasor não possa injetarGITHUB_ENV. É impossível redirecionar a compilação para algo fora do namespace Cilium. - Apenas as credenciais de CI estão no escopo. O Docker login usa
QUAY_USERNAME_CI / QUAY_PASSWORD_CI, que só pode enviar para o registro de desenvolvimento-ci. Não há credenciais de produção no executor.
O pior resultado possível de uma compilação de PR comprometida é uma imagem de CI maliciosa no registro de desenvolvimento. Esta é a mesma área de impacto que qualquer sistema de CI que constrói código de contribuidores carrega. Valorizamos cada relatório e lemos todos com atenção, mas este padrão é intencional.
CODEOWNERS como um gate de revisão
Confiamos muito no CODEOWNERS para que as alterações sempre cheguem àqueles que melhor entendem a área. Para a configuração de CI, isso significa que tudo em .github/ pertence a @cilium/github-sec (nossa equipe de CI responsável pela segurança) mais @cilium/ci-structure, e o workflow auto-approve.yaml pertence a @cilium/cilium-maintainers:
# CODEOWNERS
/.github/ @cilium/github-sec @cilium/ci-structure
/.github/ariane-config.yaml @cilium/github-sec @cilium/ci-structure
/.github/renovate.json5 @cilium/github-sec @cilium/ci-structure
/.github/workflows/ @cilium/github-sec @cilium/ci-structure
/.github/workflows/auto-approve.yaml @cilium/cilium-maintainers
Ninguém pode alterar o pipeline de CI sem uma revisão explícita da equipe responsável por sua segurança.
Bloqueando dependências
Depois de controlar quem executa as compilações, a próxima pergunta é: qual código essas compilações puxam? Um workflow fixado que puxa uma dependência comprometida permanece um workflow comprometido.
Fixando GitHub Actions por SHA digest
A coisa mais valiosa que qualquer projeto pode fazer aqui é parar de confiar em tags mutáveis.
Cada diretiva uses: em nossos arquivos de workflow se refere a ações pelo SHA completo de 40 caracteres do commit, com uma versão legível por humanos no comentário no final (fixação de ação pelo SHA completo do commit, SHA pinning):
yaml- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Se alguém comprometer a tag v6 em actions/checkout e forçar o push de código malicioso, nossos workflows não a puxarão. Eles estão fixados em um commit específico. A mesma história para cada ação de terceiros que usamos:
docker/build-push-action, sigstore/cosign-installer, golangci/golangci-lint-action e mais uma dúzia. As imagens de contêiner que são usadas diretamente nas etapas do workflow também são fixadas – por @sha256: digest, para que até mesmo as ferramentas executadas dentro do CI sejam endereçadas por conteúdo.
A fixação tem um ponto cego irritante – dependências transitivas. Quando fixamos actions/checkout@de0fac2e..., sabemos exatamente qual código está sendo executado para esta ação. Mas se actions/checkout em si se refere a outra ação por tag (uses: some-org/some-helper@v1), a resolução ocorre em tempo de execução e é invisível para nós. Um invasor que compromete uma dependência aninhada ainda pode alcançar nosso pipeline.
A correção está a caminho: o bloqueio de dependências no nível do workflow foi anunciado no roteiro de segurança do GitHub Actions para 2026. Uma seção dependencies: será adicionada ao workflow YAML, que bloqueia todas as dependências diretas e transitivas das ações por SHA do commit – semelhante ao que go.mod + go.sum fazem para Go. Conectaremos assim que estiver disponível.
Atualizações automatizadas com um limite de confiança
Manter os SHA-pins manualmente seria excruciante, então não fazemos isso. A configuração do Renovate estende o preset helpers:pinGitHubActionDigests e define pinDigests: true globalmente. Quando uma nova versão de uma ação é lançada, o Renovate abre um PR com a atualização do SHA. Permanecemos atualizados e não voltamos a um link mutável.
O Renovate funciona como um bot auto-hospedado em um cronograma de hora em hora, por meio de um GitHub App dedicado com permissões granulares em vez de um token de acesso pessoal.
vulnerabilityAlerts estão habilitados, então CVEs conhecidos na árvore de dependências se transformam imediatamente em PRs.
Recentemente, adicionamos um período de espera (cooldown) do Renovate para não capturar versões totalmente novas no momento em que são lançadas. Dado o ritmo atual de ataques à cadeia de suprimentos, alguns dias geralmente são suficientes para que um pacote comprometido seja notado e retirado (yanked):
json# .github/renovate.json5 { // Dependency cooldown: skip versions published less than 5 days ago "matchUpdateTypes": ["major", "minor", "patch"], "minimumReleaseAge": "5 days" }, { "matchPackageNames": [ "actions/{/,}**", // GitHub's official actions "docker/{/,}**", // Official Docker actions "cilium/{/,}**", // Our own ecosystem "k8s.io/{/,}**", // Kubernetes official "sigs.k8s.io/{/,}**", // Kubernetes SIGs "golang.org/x/{/,}**", // Go experimental "github.com/golang/{/,}**", // Go official org "github.com/prometheus/{/,}**", "github.com/hashicorp/{/,}**", "go.etcd.io/etcd/{/,}**", // ...trimmed ], "automerge": true, "automergeType": "pr", "groupName": "auto-merge-trusted-deps", "reviewers": ["ciliumbot"] }
As atualizações desta lista de permissões são mescladas automaticamente após passar no CI. Todo o resto requer revisão humana.
O workflow de aprovação automática adiciona outra proteção duplicada: verifica se o PR foi criado por cilium-renovate[bot] e se a solicitação de revisão foi realmente iniciada pelo próprio bot, e não por uma pessoa se passando por ele:
yamlif: ${{ github.event.pull_request.user.login == 'cilium-renovate[bot]' && (github.triggering_actor == 'cilium-renovate[bot]' || github.triggering_actor == 'auto-committer[bot]') }}
Se essas condições não forem atendidas, a aprovação automática não ocorre.
Vendoring de módulos Go
Todas as dependências Go são vendored e commitadas no repositório. O CI verifica se não há discrepâncias entre go.mod, go.sum e vendor/. As compilações são reproduzíveis e não se comunicam com proxies de módulos externos durante a compilação, então um módulo falsificado em um proxy nunca chegará até nós. Também executamos verificações de licença (go run ./tools/licensecheck) para manter dependências com licenças indesejadas fora da árvore.
Devemos fazer fork de ações para nossa própria organização?
Em teoria – sim. Se fizéssemos fork de cada ação de terceiros para cilium/ e a fixássemos no SHA do nosso fork, o comprometimento do upstream não nos alcançaria. Alguns projetos com altos requisitos de segurança fazem isso.
Decidimos não fazer isso – principalmente porque o custo operacional é real e o ganho em segurança é menor do que parece à primeira vista:
- Carga de suporte. Usamos dezenas de ações de terceiros. Sincronizar forks com patches de segurança upstream se torna uma preocupação constante, e um fork desatualizado com vulnerabilidades não corrigidas é um problema de segurança em si.
- Melhorias perdidas. As ações upstream corrigem bugs regularmente e fornecem recursos de segurança. Forks adicionam atrito e impedem que isso seja capturado.
- Complexidade do Renovate. O pipeline de atualização teria que rastrear as versões upstream, abrir PRs contra cada fork e, em seguida, atualizar os workflows consumidores. A cadeia dobra.
O SHA-pinning nos dá uma garantia realmente importante de imutabilidade: um commit específico é um commit específico, independentemente de em qual organização ele esteja. Em combinação com o Renovate, que oferece atualizações à medida que novas versões são lançadas, obtemos um ganho em segurança sem um imposto operacional. Se um grande fornecedor de ações fosse repetidamente comprometido, fazer fork de ações de alto risco seria uma escalada razoável, mas ainda não chegamos a esse ponto.
A mesma compensação – para dependências Go
A pergunta "devemos fazer fork disso?" também se aplica à nossa árvore de dependências Go. O Cilium puxa centenas de módulos Go: bibliotecas de cliente Kubernetes, gRPC, etcd, Prometheus e muito mais. Fazer fork e manter todos eles não é realista.
O Go tem uma posição inicial um pouco melhor do que npm ou PyPI, porque os caminhos de importação incluem explicitamente a fonte (github.com/stretchr/testify) – isso elimina completamente uma classe de ataques de confusão de dependência. O typosquatting, no entanto, ainda é uma ameaça real. A pesquisa de Michael Henriksen encontrou pacotes Go de typosquatting na natureza, incluindo um fork de urfave/cli registrado como utfave (uma letra transposta), que enviava o nome do host, o sistema operacional e a arquitetura para um servidor remoto. Substituir este callback por um shell reverso teria sido uma mudança de uma linha.
E o typosquatting não é o pior caso. A SolarWinds mostrou que um fornecedor legítimo e amplamente confiável pode ter seu pipeline de construção comprometido – e então distribui malware por meio de atualizações regulares. O mesmo pode acontecer com qualquer módulo Go: um invasor obtém acesso à conta do mantenedor, publica uma versão maliciosa, o proxy a armazena em cache e qualquer pessoa que execute go get a puxa. É por isso que vendoring: move a decisão de confiança do tempo de compilação, onde é invisível, para o tempo de revisão, onde uma pessoa pode ver o diff.
O vendoring é a principal defesa aqui. Um caminho de importação de typosquatting aparece como um diff em vendor/ durante a revisão do código, em vez de ser resolvido silenciosamente por meio de proxies de módulos. Isso não pega um erro de digitação no momento em que é feito (contando com o revisor para notar um caminho desconhecido no PR), mas em combinação com o gate CODEOWNERS, funciona bem até agora.
Também estamos atentos a quais dependências pegamos. A configuração do Renovate tem uma lista explícita de dependências desabilitadas que gerenciamos manualmente – seja porque precisam de atualizações coordenadas (como sigs.k8s.io/gateway-api junto com testes de conformidade), seja porque mantemos um fork com patches específicos do projeto (como github.com/cilium/dns), ou porque a dependência é algo que nós mesmos desenvolvemos e queremos atualizar intencionalmente (como github.com/cilium/ebpf – não é um fork, mas uma biblioteca Go separada mantida sob a organização Cilium). As alterações em vendor/ são revisadas por uma equipe dedicada @cilium/vendor por meio do mesmo mecanismo CODEOWNERS acima.
Há um provérbio Go que vale a pena citar: "Um pouco de cópia é melhor do que um pouco de dependência". Levamos isso a sério – além do estilo. Auditamos periodicamente bibliotecas de terceiros e reduzimos ativamente a árvore. Se uma dependência existir apenas para uma pequena função utilitária, a substituímos por algumas linhas copiadas embutidas. Cada dependência removida é uma que nunca pode ser comprometida, a árvore de vendor fica menor e a revisão de futuras alterações de dependência é simplificada. O efeito se acumula.
Capturando erros com análise estática
Mesmo com as políticas corretas, erros acontecem. Um colaborador bem-intencionado pode adicionar um workflow sem permissions: ou usar ubuntu-latest em vez de um executor fixado. Usamos análise estática para capturar isso antes da revisão.
Onde um workflow precisa de acesso de gravação (assinatura de lançamentos, OIDC para Cosign), apenas a área específica é declarada – por exemplo, id-token: write ou contents: write. Onde não é necessário – permissions: read-all ou permissions: {}, para desabilitar explicitamente os padrões mais amplos. Mas não confiamos na memória para isso. O CodeQL é executado em cada push e PR com a regra actions/missing-workflow-permissions habilitada, e o workflow falha em qualquer arquivo de workflow alterado em que as permissões não sejam especificadas explicitamente.
Além disso, o actionlint verifica estaticamente cada arquivo de workflow em busca de erros de sintaxe, padrões inseguros e configurações incorretas. O mesmo pipeline de lint também requer conformidade obrigatória com as convenções do projeto: cada job e etapa tem um nome, nenhum job usa a tag de executor flutuante ubuntu-latest (fixamos em ubuntu-24.04), não há espaço em branco à direita nos arquivos de workflow.
Uma classe de vulnerabilidade que vale a pena destacar é a injeção de expressões do GitHub Actions. A sintaxe ${{ }} no workflow YAML é uma substituição de texto que ocorre antes que o bash veja a string. Se um invasor controlar o valor substituído (título do PR, nome da branch), ele pode injetar comandos shell arbitrários por meio de ;, $(...) ou backticks. O Bash não tem ideia de onde veio o valor. A correção é primeiro atribuir o valor a uma variável de ambiente e referenciá-la como "$MY_VAR" no bloco run:, para que o bash a trate como uma única variável, independentemente do conteúdo. A equipe de segurança do GitHub nos informou sobre isso há algum tempo, e corrigimos todos os casos. É um bug sutil – fácil de introduzir e difícil de detectar na revisão, por isso a análise estática é tão importante: tanto o actionlint quanto o CodeQL marcam o uso de ${{ }} em blocos run: onde a entrada não confiável flui.
Proteção de credenciais
Partimos do princípio de que qualquer nível individual pode falhar. Se um CI-workflow for comprometido, a questão se torna: o que o invasor realmente alcançará? A resposta deve ser: nada que importe.
Padrões fortes
Por padrão, nossos GITHUB_TOKEN são limitados a permissões mínimas de leitura em conteúdos e pacotes. Os workflows que precisam de mais devem habilitar explicitamente (opt in) direitos adicionais – então um workflow que esqueceu de especificar permissões não acaba com amplo acesso de gravação em toda a organização.
Isolamento de credenciais de CI e produção
Mantemos dois conjuntos separados de credenciais de registro atrás de ambientes protegidos separados do GitHub:
- As credenciais de CI podem enviar para nosso registro de imagens de desenvolvimento (
quay.io/cilium/*-ci) e estão disponíveis para compilações de CI. Mesmo que um CI-workflow seja comprometido de alguma forma, essas credenciais não poderão enviar para tags de imagens de produção. - As credenciais de produção estão atrás do ambiente
release, que requer aprovação explícita do mantenedor antes que a execução do workflow possa tocá-las. Nem um fork, nem uma branch de recurso, nem uma compilação de CI obterão esses segredos. Apenas compilações de lançamento acionadas por tag que um mantenedor aprovou.
No pior caso de comprometimento do CI, um invasor pode publicar uma imagem -ci maliciosa. Não será possível publicar em quay.io/cilium/cilium:v1.x.x ou docker.io/cilium/cilium:v1.x.x. As credenciais simplesmente não estão no executor.
Cada chamada para actions/checkout também define persist-credentials: false, para que o GITHUB_TOKEN nunca acabe na configuração git do executor, de onde uma etapa posterior poderia pegá-lo.
Assinando e atestando o que entregamos
As seções anteriores são sobre como impedir que coisas ruins entrem no pipeline. Esta é sobre dar aos consumidores a capacidade de verificar o que sai dele.
Cada imagem de contêiner que lançamos (cilium, operator-*, hubble-relay, clustermesh-apiserver) é assinada usando o Sigstore Cosign via OIDC sem chave. Não há chaves de assinatura de longa duração que possam ser roubadas.
Uma ação composta reutilizável lida com o pipeline de assinatura:
yaml# .github/actions/cosign/action.yaml - name: Install Cosign uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1 - name: Generate SBOM uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 with: artifact-name: sbom_${{ inputs.sbom_name }}.spdx.json output-file: ./sbom_${{ inputs.sbom_name }}.spdx.json image: ${{ inputs.image_tag }} - name: Sign Container Image shell: bash run: cosign sign -y "${{ inputs.image }}" - name: Attach SBOM Attestation shell: bash run: | cosign attest -y \ --predicate "./sbom_${{ inputs.sbom_name }}.spdx.json" \ --type spdxjson \ "${{ inputs.image }}"
Isso é executado para cada compilação de imagem de lançamento e para nossos artefatos OCI de gráficos Helm. As instruções de verificação estão na documentação do Cilium.
As compilações de lançamento também são executadas dentro de ambientes protegidos (release, release-tool, release-helm), para que as credenciais do registro de produção sejam limitadas pelas regras de proteção do ambiente. Não é possível executar uma compilação de lançamento a partir de um fork ou branch de recurso.
Equipe de segurança do Cilium
Se você já relatou um problema de segurança ao projeto (por meio de avisos de segurança do GitHub ou security@cilium.org), você já...








