Skip to main content

Ferramentas para detectar desvios na infraestrutura

Escrito por
Headshot of William Beuil

William Beuil

feature iac drift blue

15 de março de 2022

0 minutos de leitura

Aviso de descontinuação: detecção de drift em recursos gerenciados

A detecção de drift em recursos gerenciados, incluindo snyk iac describe --only-managed and snyk iac describe --drift, foi descontinuada. A detecção de drift em recursos gerenciados será encerrada em 30 de setembro de 2023.

Prever desvios na infraestrutura é como prever neve no inverno… você sabe que vai acontecer em algum momento, mas não exatamente quando. E, assim como a neve, quanto mais cedo você conseguir detectar os desvios, mais preparado estará e mais segura será sua infraestrutura!

Neste artigo, vamos explorar os princípios da detecção de desvios, os diferentes tipos e por que eles acontecem, além de ferramentas para detectá-los com um exemplo simples.

O que é detecção de desvios?

Para entender por que você precisa de uma ferramenta para detectar desvios, é importante compreender o que é desvio na infraestrutura. Em resumo, é possível pensar nele como uma divergência entre toda a sua infraestrutura e o arquivo de configuração.

Neste artigo, vamos usar o HashiCorp Terraform como ferramenta de infraestrutura como código (IaC) para implantar recursos na nuvem. No universo do Terraform, um desvio — ou divergência na infraestrutura — ocorre quando o arquivo de estado não corresponde ao que foi aplicado no seu provedor de nuvem.

É aí que uma ferramenta adequada para detectar esses desvios pode melhorar significativamente sua postura de segurança. Imagine um mundo ideal em que você recebe alertas quando alguém altera manualmente seu grupo de segurança em vez de usar o Terraform. E não seria ótimo receber alertas sobre recursos criados fora do Terraform?

Recursos gerenciados e não gerenciados

Para ilustrar esse cenário ideal, vamos diferenciar dois tipos de desvio:

Desvios em recursos gerenciados por IaC

Como temos os arquivos de configuração e de estado de todos os recursos aplicados e implantados no seu provedor de nuvem, sua ferramenta de IaC geralmente é adequada para ajudar a detectar alterações feitas fora dela ou que ainda não foram aplicadas.

Desvios em recursos não gerenciados por IaC

Por outro lado, esse tipo de desvio é difícil de detectar, já que esses recursos nem sequer estão definidos no arquivo de configuração ou de estado.

Por que os desvios acontecem?

Os desvios acontecem por muitos motivos óbvios, mas ninguém explica melhor do que a HashiCorp:

"No contexto da sua configuração, isso acontece quando recursos são adicionados ou removidos, ou quando suas definições são alteradas. Fora da sua configuração, o desvio ocorre quando recursos são encerrados ou apresentam falhas, e quando mudanças são feitas manualmente ou por meio de outras ferramentas de automação."

HashiCorpHashiCorp

Christie Koehler

Developer Advocate, HashiCorp

Vamos analisar exemplos reais dos dois tipos de desvio e seus impactos. Um desvio em um recurso gerenciado pode ocorrer quando alguém altera manualmente o controle de versão de um bucket do Amazon S3 configurado no Terraform. Já um desvio em um recurso não gerenciado pode ocorrer quando alguém cria manualmente um bucket do S3 fora do Terraform (por exemplo, no console da AWS). (Confira nosso artigo anterior com dicas para gerenciar desvios causados por alterações manuais.)

Quais ferramentas podem ajudar a detectar esses desvios?

Agora vamos nos concentrar em ferramentas que ajudam a detectar desvios em recursos gerenciados e não gerenciados. No restante deste artigo, usaremos o mesmo exemplo simples de Terraform apresentado acima:

resource "aws_s3_bucket" "example" {
        bucket = "drift-example-managed-resource"
        versioning {
                enabled = true
        }
}

Vamos alterar no console o atributo de controle de versão para false, criando um desvio. Além disso, vamos criar manualmente o mesmo bucket do S3 no console da AWS.

Console do AWS S3 Buckets mostrando exemplos de buckets gerenciados e não gerenciados na região Oeste dos EUA (Oregon), ambos marcados como privados.

Agora, vamos conhecer três ferramentas para gerenciar desvios:

  1. terraform plan

  2. CloudQuery

  3. driftctl

1. terraform plan

O comando terraform plan descreve o que precisa ser aplicado para que você alcance a implementação desejada. Veja o resultado desse comando na nossa infraestrutura:

$ terraform plan

aws_s3_bucket.example: Refreshing state... [id=drift-example-managed-resource]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply":

  # aws_s3_bucket.example has changed
  ~ resource "aws_s3_bucket" "example" {
        id                          = "drift-example-managed-resource"
        # (10 unchanged attributes hidden)

      ~ versioning {
          ~ enabled    = true -> false
            # (1 unchanged attribute hidden)
        }
    }

Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.

────────────────────────────────────────────────────────────
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_s3_bucket.example will be updated in-place
  ~ resource "aws_s3_bucket" "example" {
        id                          = "drift-example-managed-resource"
        # (10 unchanged attributes hidden)

      ~ versioning {
          ~ enabled    = false -> true
            # (1 unchanged attribute hidden)
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

O Terraform informa que encontrou um desvio no recurso gerenciado e explica qual foi a alteração (por exemplo, o controle de versão passou de true para false). Em seguida, mostra o que fará se decidirmos aplicar o plano (por exemplo, voltar o controle de versão para true).

Vantagens:

  • Forma consistente de detectar desvios em recursos gerenciados

  • Compatibilidade com todos os recursos do Terraform

Desvantagens:

  • Não detecta desvios em recursos não gerenciados

  • Não oferece suporte a planos em vários arquivos de estado

2. CloudQuery

O CloudQuery é um inventário de ativos na nuvem de código aberto, baseado em SQL. Por padrão, ele extrai todos os recursos dos provedores de nuvem desejados, formata os dados e os carrega no PostgreSQL. A ferramenta oferece um comando de detecção de desvios para “transformar esse problema de desvio em um problema de dados”, como eles dizem.

Depois de instalar a CLI do CloudQuery, vamos voltar à detecção de desvios nos nossos buckets do S3.

$ cloudquery fetch

Initializing CloudQuery Providers...

✓ cq-provider-aws@v0.10.10 verified    0s  100 %

Finished provider initialization...

Upgrading CloudQuery providers aws

✓ Upgraded provider aws to latest successfully.

Finished upgrading providers...

Starting provider fetch...

✓ cq-provider-aws@latest fetch complete   15s   Finished Resources: 129/129

Provider fetch complete.

Provider aws fetch summary: ✓ Total Resources fetched: 523 ⚠️ Warnings: 0 ❌ Errors: 0

Como explicado acima, o primeiro comando busca todos os recursos nos meus provedores de nuvem e os insere em uma tabela do PostgreSQL.

Tabela escura de banco de dados mostrando recursos gerenciados e não gerenciados, com o status de versionamento indicado como Suspenso e Ativado.
$ cloudquery drift scan --deep --debug terraform.tfstate

Initializing CloudQuery Providers...

⌛cq-provider-aws@v0.10.11 downloading...                           4s  100 %

Finished provider initialization...

Using profile drift-example
Starting module...
DIFF RESOURCE: s3.buckets:drift-example-managed-resource
+------------------------------------------+-----------+---------------+-------------------------+
|                 AWS EXPR                 |  AWS VAL  | TERRAFORM VAL |     TERRAFORM EXPR      |
+------------------------------------------+-----------+---------------+-------------------------+
| COALESCE("c"."versioning_status",'')     | Suspended | <nil>         | versioning_status       |
| COALESCE("c"."versioning_mfa_delete",'') | Disabled  | <nil>         | versioning_mfa_delete   |
| "c"."block_public_acls"                  | true      | <nil>         | block_public_acls       |
| "c"."block_public_policy"                | true      | <nil>         | block_public_policy     |
| "c"."ignore_public_acls"                 | true      | <nil>         | ignore_public_acls      |
| "c"."restrict_public_buckets"            | true      | <nil>         | restrict_public_buckets |
+------------------------------------------+-----------+---------------+-------------------------+
Matching attributes "region", "logging_target_prefix", "logging_target_bucket", "policy", "tags", "replication_role", "arn", "ownership_controls"
+-----------------------+---------------------------------------------------------+
|       ATTRIBUTE       |                     MATCHING VALUE                      |
+-----------------------+---------------------------------------------------------+
| region                | us-west-2                                               |
| logging_target_prefix |                                                         |
| logging_target_bucket |                                                         |
| policy                | <nil>                                                   |
| replication_role      |                                                         |
| arn                   | arn:aws:s3:::drift-example-managed-resource             |
| ownership_controls    | <nil>                                                   |
+-----------------------+---------------------------------------------------------+
Module output:
=== DRIFT RESULTS  ===
1 Resources not managed by Terraform
  aws:s3.buckets:
    - drift-example-un-managed-resource
1 Resources managed by Terraform but drifted
  aws:s3.buckets:
    - drift-example-managed-resource
=== SUMMARY ===
Total number of resources: 2
 - 1 not managed by Terraform
 - 1 managed by Terraform but drifted
 - 50% covered by Terraform
Finished module

Esse resultado é interessante: podemos ver que a ferramenta encontrou meus dois buckets do S3, um gerenciado e outro não gerenciado. Além disso, ela detectou um desvio no bucket gerenciado, mas a análise é um tanto estranha: informou que o bucket do S3 não tem controle de versão na AWS, mas que o estado é desconhecido no meu arquivo de estado. Provavelmente, há um bug na forma como a ferramenta analisa os atributos do Terraform. Os outros atributos com desvio me deixam em dúvida sobre o que aconteceria se eu tivesse um bucket gerenciado sem desvios.

Apliquei novamente a configuração inicial do bucket com terraform apply e repeti os comandos cloudquery fetch e cloudquery drift scan --deep --debug terraform.tfstate:

$ terraform plan

aws_s3_bucket.example: Refreshing state... [id=drift-example-managed-resource]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

$ cloudquery drift scan --deep --debug terraform.tfstate

...

DIFF RESOURCE: s3.buckets:drift-example-managed-resource
+------------------------------------------+----------+---------------+-------------------------+
|                 AWS EXPR                 | AWS VAL  | TERRAFORM VAL |     TERRAFORM EXPR      |
+------------------------------------------+----------+---------------+-------------------------+
| COALESCE("c"."versioning_status",'')     | Enabled  | <nil>         | versioning_status       |
| COALESCE("c"."versioning_mfa_delete",'') | Disabled | <nil>         | versioning_mfa_delete   |
| "c"."block_public_acls"                  | true     | <nil>         | block_public_acls       |
| "c"."block_public_policy"                | true     | <nil>         | block_public_policy     |
| "c"."ignore_public_acls"                 | true     | <nil>         | ignore_public_acls      |
| "c"."restrict_public_buckets"            | true     | <nil>         | restrict_public_buckets |
+------------------------------------------+----------+---------------+-------------------------+
…

O CloudQuery ainda detectou um desvio no meu bucket, alterando o status do controle de versão na tabela de dados. Isso é claramente um falso positivo, que não deve ser considerado, já que o controle de versão está ativado no bucket pelo console da AWS.

Vantagens:

  • Enumeração muito rápida dos recursos na nuvem com o comando fetch

  • Detecção de recursos não gerenciados com o simples comando drift scan

  • Suporte à análise de vários arquivos de estado

Desvantagens:

  • Resultados pouco confiáveis para atributos com desvio em buckets do S3 com o comando drift scan --deep --debug

  • Compatibilidade com poucos backends para armazenar arquivos de estado (por exemplo, S3 e armazenamento local)

  • Não oferece suporte a todos os recursos do Terraform

  • Exige um banco de dados SQL

3. driftctl

O driftctl é uma ferramenta CLI de código aberto e gratuita que alerta sobre desvios na infraestrutura. Ela ajuda a detectar, acompanhar e emitir alertas sobre desvios em recursos gerenciados e não gerenciados. Vamos testar com nosso exemplo. Observação: o driftctl é o mecanismo de detecção de desvios de código aberto da própria Snyk.

$ driftctl scan --deep

Scanned states (1)
Found resources not covered by IaC:
  aws_s3_bucket:
    - drift-example-un-managed-resource
Found changed resources:
  From tfstate://terraform.tfstate
    - drift-example-managed-resource (aws_s3_bucket.example):
        ~ versioning.0.enabled: true => false
Found 2 resource(s)
 - 50% coverage
 - 1 resource(s) managed by Terraform
     - 1/1 resource(s) out of sync with Terraform state
 - 1 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider
Scan duration: 17s
Provider version used to scan: 3.74.3. Use --tf-provider-version to use another version.

Esse resultado mostra que o driftctl encontrou nossos dois recursos. O recurso gerenciado foi identificado com um atributo em desvio: o status do controle de versão. O outro recurso é nosso bucket do S3 não gerenciado.

Vantagens:

  • Detecta atributos com desvio em recursos gerenciados com o driftctl scan --deep command

  • Detecta desvios em recursos não gerenciados com o driftctl scan command

  • Oferece suporte à análise de vários arquivos de estado

Desvantagens:

  • A análise no modo --deep pode demorar bastante, pois lista todos os recursos de uma conta e busca os detalhes de cada um

  • Erros de limitação de chamadas à API durante a análise, pois a ferramenta depende muito da API do provedor de nuvem para reunir todas as informações

  • Não oferece suporte a todos os recursos do Terraform

O que considerar ao escolher ferramentas para detectar desvios

Essas três ferramentas fazem muito bem o que se propõem a fazer. Vamos resumir os cenários em que cada uma se destaca.

O comando terraform plan é uma ferramenta muito poderosa, que você pode usar em um pipeline agendado para todos os seus arquivos de estado. Assim, além de contar com cobertura para todos os recursos, você tem uma forma universal e fácil de entender de apresentar atributos com desvios. A única desvantagem é não poder agregar todos os arquivos de estado e executar o comando em um único lugar para verificar quais recursos têm desvios. Informar recursos não gerenciados não é função da ferramenta, mas é essencial.

Já os resultados da ferramenta de linha de comando CloudQuery são variados. Por um lado, o comando de enumeração (fetch) é uma tecnologia impressionante. Você tem acesso gratuito a uma alternativa de código aberto que oferece visibilidade profunda da infraestrutura na nuvem, usando SQL como mecanismo de consulta e políticas. Por outro lado, o comando de detecção de desvios é bastante limitado. Com base nos meus testes, não dá para confiar nele para encontrar desvios em recursos gerenciados. Além disso, só é possível usar a ferramenta para encontrar recursos não gerenciados em cenários simples: você precisa ter acesso ao arquivo de estado localmente (na maioria das vezes, para testar a ferramenta) ou por meio de um bucket do S3 (a prática recomendada para testá-la em CI). Felizmente, o comando de detecção de desvios ainda está em versão alfa. Mal posso esperar para ver essa ferramenta de linha de comando evoluir.

Com o driftctl integrado à sua CI e executado diariamente, você recebe alertas contínuos sobre desvios em recursos gerenciados e não gerenciados. A variedade de backends compatíveis para armazenar arquivos de estado faz dele uma boa opção para a maioria das infraestruturas. Além disso, assim como no CloudQuery, você pode filtrar ou ignorar recursos que não são relevantes e gerar relatórios de acordo com suas necessidades. Uma limitação séria, decorrente do design do driftctl, é que infraestruturas muito grandes podem dificultar sua execução, devido à limitação de chamadas à API. Por fim, a execução no modo --deep pode ser incômoda durante testes locais em infraestruturas grandes, mas é menos problemática em um pipeline de CI.

Por último, mas não menos importante: as permissões. Nem o driftctl nem o CloudQuery precisam do seu código Terraform; basta o arquivo de estado, o que simplifica o processo. Ambos seguem a prática recomendada de conceder o mínimo de permissões necessárias para analisar todo o seu provedor de nuvem. Isso significa que uma política somente de leitura basta para executar os dois comandos. O mesmo não vale para o comando do Terraform, que precisa de permissões de leitura e gravação para criar, atualizar ou excluir sua infraestrutura, além de ler seu código para saber o que implantar ou remover.

O que vem por aí no Snyk IaC

Se você quer colocar recursos não gerenciados sob o controle de IaC e também detectar desvios em recursos gerenciados, a Snyk pode ajudar. O gerenciamento de desvios no Snyk IaC ajuda você a proteger a infraestrutura com mais rapidez, informando problemas e correções diretamente aos desenvolvedores, em uma linguagem feita para eles. Com um ciclo de feedback mais rápido entre as equipes de segurança na nuvem e de desenvolvimento, os desenvolvedores podem assumir a responsabilidade pelo Terraform, do código à nuvem, e proteger as configurações da infraestrutura após a implantação. A solução também identifica recursos não gerenciados em ambientes de nuvem, para que você possa colocá-los sob controle de IaC e reduzir desde o início o risco de desvios.

Recursos adicionais sobre gerenciamento de desvios

Para continuar aprendendo sobre o gerenciamento de desvios no Terraform, confira mais alguns artigos do nosso blog:

Proteja a infraestrutura desde a origem

A Snyk automatiza a segurança e a conformidade de IaC nos fluxos de trabalho e detecta recursos com configurações divergentes ou ausentes.