Harbor: Container Registry Seguro e Grátis
Tags: devops, ptbr, docker, kubernetes
Published: 2020-05-17 05:01:14


#### TL;DR

:warning: Isso não é um tutorial! :warning: 

Aqui dou um review geral sobre o [Harbor](https://goharbor.io/), um repositório de imagens OCI compliant com diversas features interessantes criado pela VMware e que hoje está sob a [CNCF](https://www.cncf.io/). Entre todas as suas funcionalidades, as mais interessantes são as de segurança, onde tento dar um pouco mais de detalhes. É uma ferramenta consideravelmente fácil de manter, se configurada da forma correta, e que agora conta a nova versão 2.0.

## **Tópicos**

* :computer: [INSTALAÇÃO](#instalacao)
* :closed_lock_with_key: [SEGURANÇA](#seguranca)
	* :no_entry_sign: [Controle de Acesso](#controledeacesso)
	* :robot: [Robot Accounts](#robotaccounts)
	* :eyes: [Scan de Vulnerabilidades (Trivy)](#scan)
	* :key: [Content Trust (Notary)](#notary)
* :gem: [FUNCIONALIDADES](#funcionalidades)
	* :zzz: [Automação](#automacao)
	* :alarm_clock: [Tag Retention](tagretention)
	* :pushpin: [Tag Immutability](tagimmutability)
	* :dancers: [Replication](#replication)
	* :neutral_face: [Labels](#labels)
	* :minidisc: [Project Quotas](#projectquotas)
* :star: [BÔNUS](#bonus)
	* :memo: [Terraform Provider](#terraform)
	* :bug: [Docker](#docker)
* :beers: [CONCLUSÃO](#conclusao)

Olá.

Conforme o tempo passa, torna-se importante e urgente termos algum sistema de armazenamento e gerência de imagens que seja centralizado. Se você chegou nesse momento, antes de sair procurando por soluções pagas, sugiro que dê uma olhada na opção que vou apresentar.

Quando falamos sobre Container Registry desconheço uma tecnologia com tantas funcionalidades e que seja totalmente opensource como o Harbor. O objetivo desse texto é dar um review em português sobre algumas features legais, boas práticas, falar um pouco da minha experiência e também sobre alguns desafios que tive.

Tenho usado bastante o Harbor no meu trabalho e, com o lançamento da versão 2.0 achei bacana escrever algo a respeito, já que é bem difícil achar informação do Harbor em nossa língua. Com essa nova versão, o Harbor se consolida ainda mais dentro da CNCF sendo oficialmente o primeiro container registry opensource OCI compliant do mercado, capaz de gerenciar múltiplos artefatos Cloud Native, como Helm charts, OPAs, Singularity e etc.

Se quiser saber mais sobre a versão 2.0, sugiro a leitura [desse post oficial](https://goharbor.io/blog/harbor-2.0/). 

**PS:** Para que minha lista de referências não fique gigante e perdida no final do texto, resolvi ir linkando enquanto escrevo toda documentação, issues, etc, para ficar mais fácil de acompanhar. :+1: <a name="instalacao"></a>

&nbsp;
### :computer: INSTALAÇÃO 

Por mais que o quick-install com o docker-compose seja convidativo pela sua facilidade, sugiro que dê preferência para o [Helm chart](https://goharbor.io/docs/2.0.0/install-config/harbor-ha-helm/) ou para o [Operator](https://github.com/goharbor/harbor-operator) (*tech preview*), por motivos claros de facilitar o controle de versão, alterações e manutenções futuras no ambiente. O principal benefício de usar o Helm ou o Operator é também ter a possibilidade de instalar o Harbor com alta disponibilidade.

A instalação permite que você configure toda a persistência de dados de forma externa, como por exemplo, usando os serviços S3 (object storage), RDS (postgres) e Elasticache (redis) da AWS para armazenar imagens, configurações e cache da ferramenta.

Se você optar por expor o serviço via loadBalancer na AWS, use essa annotation para garantir que este seja somente interno: `service.beta.kubernetes.io/aws-load-balancer-internal: "true"`

Considere também usar TLS desde o início, a versão 2.0 do Harbor trouxe melhorias para esse ponto, onde agora todos os componentes se comunicam de forma mais segura. Além disso, SSL é obrigatório para o funcionamento de algumas features do Harbor, como a assinatura de imagens. <a name="seguranca"></a>

&nbsp;
### :closed_lock_with_key: SEGURANÇA 

Aproveitando o gancho do TLS, o Harbor possui algumas features de segurança que acho legal comentar:
<a name="controledeacesso"></a>
####&nbsp;&nbsp;&nbsp;&nbsp;:no_entry_sign: [Controle de Acesso:](https://goharbor.io/docs/2.0.0/administration/managing-users/) 

Atualmente o Harbor possui compatibilidade com [autenticação de usuários externos](https://goharbor.io/docs/2.0.0/administration/configure-authentication/) oidc, ldap, etc. E também fornece suporte total para RBAC com controle de acesso por grupos.
<a name="robotaccounts"></a>
####&nbsp;&nbsp;&nbsp;&nbsp;:robot: [Robot Accounts:](https://goharbor.io/docs/2.0.0/working-with-projects/project-configuration/create-robot-accounts/) 

São contas de serviço que não possuem acesso à console e têm uso bem restrito dentro dos projetos, ideal para usar no pipeline, mas...

Existe um [Feature Request](https://github.com/goharbor/harbor/issues/10774) na comunidade para permitir a criação de RAs com acesso à múltiplos projetos, uma vez que em um pipeline essa necessidade é bem comum. A equipe de desenvolvimento planeja essa feature para a versão 2.1 do Harbor.
<a name="scan"></a>
####&nbsp;&nbsp;&nbsp;&nbsp;:eyes: [Scan de Vulnerabilidades (Trivy):](https://goharbor.io/docs/2.0.0/administration/vulnerability-scanning/) 

Até a versão 1.10, o scanner padrão da ferramenta era o Clair, padrão Coreos, mas a partir da 2.0, o [Trivy](https://github.com/aquasecurity/trivy) passa a acompanhar o Harbor como scanner oficial. Para quem usa a versão 1.10 ou inferior, como eu, é possível substituir o default pelo Trivy de maneira simples e totalmente suportada usando o chart [harbor-scanner-trivy](https://github.com/aquasecurity/harbor-scanner-trivy).

O Trivy possui muitas [vantagens](https://github.com/aquasecurity/trivy#vs-clair) sobre o Clair, como validação de todos os layers de uma imagem ao invés de somente do resultado final dela, scan de os **e libs**, além de uma base com mais informações de vulnerabilidades. 

Você também pode usar o [trivy client](https://github.com/aquasecurity/trivy#scan-an-image) para scannear suas imagens localmente, e até integrar em seu pipeline para garantir que imagens vulneráveis nem cheguem a ser carregadas em seu registry.

Por padrão, o trivy client não consegue se comunicar com o Trivy que opera no Harbor, pois são protocolos de comunicação diferentes (HTTP vs TWIRP).

Isso me fez ter que criar um deployment com o Trivy em meu cluster só para poder usar uma base de cache centralizada de consulta via twirp, ao invés de gerar uma nova base a cada scan local. Não que isso seja grande coisa, mas com o tempo você vai notar que essa base de cache do Trivy pode ocupar um pouco de espaço.

**PS:** Como o Trivy sempre faz esse cache das análises, caso você altere uma imagem e use a mesma tag para ela, o Trivy vai usar informações do cache para análise, ou seja, replicar a análise da imagem anterior, isso acontece com a tag `latest` por exemplo. Para resolver isso, evite usar a tag latest :kissing_heart:, ou use opção `--clear-cache` no command line do trivy, para que ele refaça o DB de cache dessa imagem.

Hoje, para scannear as imagens em um pipeline usando docker, acessando um Trivy server externo (twirp), você pode usar o seguinte comando:

~~~shell
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy client --remote http://scan-yourharbor.domain.com --ignore-unfixed --quiet [YOUR_IMAGE_NAME]
~~~

Isso se você quiser realizar o scan da sua imagem antes de enviar ao Harbor, pois dentro dele você também pode definir regras como:

* Scan automático de imagens após um push;
* Impedir pull de imagens com determinada severidade;
* Realizar tarefas de scan, scan report, etc, via API do próprio Harbor.

Recentemente abri um [Feature Request](https://github.com/aquasecurity/harbor-scanner-trivy/issues/77) no github da aquasecurity para permitir a exposição de um endpoint twirp no Trivy que integra o Harbor, isso eliminaria a necessidade de ter que criar um deployment separado para um Trivy server. <a name="notary"></a>

####&nbsp;&nbsp;&nbsp;&nbsp;:key: [Content Trust (Notary):](https://goharbor.io/docs/2.0.0/working-with-projects/project-configuration/implementing-content-trust/) 

O [Notary](https://github.com/theupdateframework/notary) é um sistema já conhecido e usado junto com o docker para realizar a assinatura de imagens e, se você quiser, pode usar ele integrado com o Harbor. O requisito é ter TLS configurado e uma tabela a mais no seu banco de dados para uso dele.

Você precisa configurar uma secret específica no k8s com os crts apontando para os service names do notary-server e notary-signer (kubectl get svc). Depois insira os crts (tls.crt, tls.key e ca.crt) no client que for usar o notary em: `~/.docker/tls/yourharbor.domain.com:4443`

Para usar o notary é simples. Achei esse vídeo no youtube que, apesar de ser antigo, o procedimento segue o mesmo:

{% youtube pPklSTJZY2E%}

Note que imagens assinadas não podem ser deletadas no Harbor, é necessário excluir a assinatura da imagem anteriormente para depois deletar no projeto.
Para excluir a chave da imagem é necessário obter o [client do notary](https://github.com/theupdateframework/notary/releases) e usar o seguinte command line:

~~~shell
$ ./notary -s https://yourharbor.domain.com:4443 --tlscacert ~/.docker/tls/yourharbor.domain.com:4443/ca.crt -d ~/.docker/trust remove -p yourharbor.domain.com/teste-signed/imagem tag
~~~

Caso você não tenha a chave da imagem que deseja remover a assinatura localmente, utilize o seguinte comando:

~~~shell
$ ./notary -s https://yourharbor.domain.com:4443 --tlscacert ~/.docker/tls/yourharbor.domain.com:4443/ca.crt delete yourharbor.domain.com/teste-signed/trivy --remote
~~~

Por não ter uma API tão atualizada, o Notary não se dá muito bem com algumas funcionalidades do Harbor, como o :bug: [Tag Retention](https://github.com/goharbor/harbor/issues/10115) e a :bug: [replicação entre outros servidores Harbor](https://github.com/goharbor/harbor/issues/8303).

Cada escolha, uma renúncia. :stuck_out_tongue_closed_eyes: Mas a comunidade já está trabalhando em uma v2 para a api do Notary.

De qualquer forma, você pode usar o Notary em repositórios de produção que talvez não exijam prunes tão frequentes e usar o tag retention em repositórios que possuem bastante alteração. <a name="funcionalidades"></a>

&nbsp;
### :gem: FUNCIONALIDADES <a name="automacao"></a>

Vou citar aqui as funcionalidades mais chamativas e que tive mais experiência, mas não se limite a esse texto, na documentação há muito mais informações.

####&nbsp;&nbsp;&nbsp;&nbsp;:zzz: Automação: 

O Harbor possui algumas features que facilitam bastante nossas automações como a utilização de [webhooks](https://goharbor.io/docs/2.0.0/working-with-projects/project-configuration/configure-webhooks/) nos projetos, que também teve melhorias na versão 2.0. Além de ser possível realizar praticamente qualquer atividade somente com a sua API usando basic auth:

~~~shell
$ curl -u User:Token -X GET ...
~~~

Você pode conferir todas as chamadas possíveis no menu [API EXPLORER](https://goharbor.io/docs/2.0.0/working-with-projects/using-api-explorer/) da console. <a name="tagretention"></a>


####&nbsp;&nbsp;&nbsp;&nbsp;:alarm_clock: [Tag Retention:](https://goharbor.io/docs/2.0.0/working-with-projects/working-with-images/create-tag-retention-rules/) 

Configure uma regra para deletar imagens com mais de X dias, ou para manter apenas os x últimos pushs. São muitas as possibilidades aqui, mas lembre-se de não usar o Tag Retention caso esteja usando imagens assinadas com o Notary, pois essa funcionalidade não é capaz de apagar as chaves ao fazer o prune. <a name="tagimmutability"></a>


####&nbsp;&nbsp;&nbsp;&nbsp;:pushpin: [Tag Immutability:](https://goharbor.io/docs/2.0.0/working-with-projects/working-with-images/create-tag-immutability-rules/) 

Por default, usuários podem fazer o push de uma mesma imagem:tag várias vezes e isso faz com que a imagem sobrescrita fique sem tag (*tagless*). Isso acontece porque o próprio upstream do docker não força o mapeamento entre tag e digest. Dessa forma, você mesmo pode impedir que tags sejam modificadas no Harbor, simples assim, isso pode evitar MUITOS problemas. <a name="replication"></a>


####&nbsp;&nbsp;&nbsp;&nbsp;:dancers: [Replication:](https://goharbor.io/docs/2.0.0/administration/configuring-replication/) 

Você pode configurar outros registries para o seu ambiente se conectar (no menu Registries), podendo ser o Docker Hub, Helm Hub e até outro Harbor, a lista é bem extensa. :sunglasses:

O legal aqui é que você pode configurar schedules para o Harbor realizar pull de imagens dos Hubs (imagens, charts, etc) para dentro dos seus projetos, podendo assim, sempre manter suas imagens e charts na última versão, por exemplo. Isso tudo é feito através do menu de Replication.

Ou ainda, você pode realizar o push dos seus artefatos para outros repositórios como Amazon ECR, Google ou até mesmo para outra instância Harbor. Tudo isso com filtros especificos para projetos, repositórios, tags, etc. <a name="labels"></a>


####&nbsp;&nbsp;&nbsp;&nbsp;:neutral_face: Labels: 

Eu particularmente não gostei, essa feature acompanhou o Harbor até a versão 1.10. A princípio, achei que eu pudesse relacionar com as labels que usamos no Dockerfile, mas não tem nada a ver. Labels do Dockerfile, como a gente sabe, são key=value e, no Harbor o funcionamento é bem diferente. Daí fica um pouco difícil de integrar, tanto que foi removido na versão 2.0. Mas existe uma [discussão](https://github.com/goharbor/harbor/issues/7175) para fazer isso direito no projeto futuramente.
<a name="projectquotas"></a>
####&nbsp;&nbsp;&nbsp;&nbsp;:minidisc: [Projetc Quotas:] (https://goharbor.io/docs/2.0.0/administration/configure-project-quotas/) 

Funciona e é bem intuitivo, mas não recomendo usar, é mais uma coisa para ficar olhando. Acredito que seja mais vantajoso trabalhar bem o controle de acesso do Harbor junto com boas regras de Tag Retention para evitar o uso/upload exagerado e desnecessário de imagens. Assim, você garante que o que está no Harbor tem que estar lá. <a name="bonus"></a>

&nbsp;
### :star: BÔNUS <a name="terraform"></a>

Algumas menções importantes:

####&nbsp;&nbsp;&nbsp;&nbsp;:memo: Terraform Provider:

Existem algumas iniciativas na comunidade do Terraform para gerência das configurações do Harbor que são bem interessantes como [essa](https://github.com/BESTSELLER/terraform-harbor-provider), que inclusive está citada na página de community providers do Terraform, e também [essa outra](https://github.com/Ouest-France/terraform-provider-harbor). Isso facilita a criação, padronização e versionamento dos projetos que você administra no Harbor. <a name="docker"></a>

####&nbsp;&nbsp;&nbsp;&nbsp;:bug: Docker:

Alguns comportamentos inesperados no Harbor ocorrem por conta de problemas na própria engine do docker, como o caso do tag immutability que comentei anteriormente. Outro caso importante de mencionar é o de [imagens com 0 Bytes que não podem ser deletadas](https://github.com/goharbor/harbor/issues/6515). Isso acontece quando tentamos deletar várias tags que referenciam o mesmo digest, por exemplo, a tag latest e a versão 1.0.0 que são a mesma imagem. Uma delas vai ficar com 0 Bytes por já ter tido o digest deletado. Existe um [workaround](https://github.com/goharbor/harbor/issues/6515#issuecomment-593051531) para isso, mas o problema ocorre por um bug no próprio [upstream](https://github.com/docker/distribution/issues/1755) do docker. <a name="conclusao"></a>


&nbsp;
### :beers: CONCLUSÃO 

O Harbor está em constante desenvolvimento na comunidade e pode tranquilamente ser utilizado como container registry em sua empresa. A documentação não é muito extensa ainda, mas tem praticamente tudo o que você precisa para operá-lo com tranquilidade e, caso necessite de apoio da comunidade, basta abrir um issue no github do componente que você está com dificuldades, expondo o máximo de detalhes sobre como reproduzir seu problema.

O camarada [Matheus Fidelis](https://twitter.com/fidelissauro) está fazendo uma série de vídeos no Youtube chamada [#CNCFChallenge](https://www.youtube.com/watch?v=pFstphlh5A8&list=PLsyPhquWMjqEBjY0neO8R7qGIRP0Kkwm3) promovendo o estudo de tecnologias CNCF, e ele já falou sobre o Harbor lá no lab dele. Vale a pena dar uma conferida.

{% youtube c-1Xw7TcrCs%}

Qualquer dúvida, crítica ou sugestão, pode me procurar no [Twitter](https://twitter.com/vzanlnx).