Skip to main content

Ampliando a cobertura dos recursos em nuvem para reduzir o drift da infraestrutura

Escrito por
Headshot of Stephane Jourdan

Stephane Jourdan

feature iac drift purple

23 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.

Como desenvolvedores, precisamos ter visibilidade máxima do que está realmente em execução nos nossos ambientes de nuvem para mantê-los seguros. A infraestrutura como código (IaC) ajuda a automatizar as infraestruturas em nuvem, garantindo que o que é implantado na nuvem esteja sob controle e possa ser auditado com facilidade. Mas alcançar e manter 100% de cobertura de IaC na infraestrutura traz muitos desafios.

Nossa segurança depende do que está realmente implantado e em execução nos ambientes de nuvem. E, muitas vezes, nós, outras equipes ou alguns serviços autenticados ainda realizamos ações manuais com frequência. Essas alterações ficam ocultas para a IaC e para as auditorias, causando problemas como configurações incorretas e riscos de segurança. É aí que o gerenciamento de drift se torna importante: queremos relatórios dos recursos que ainda não estão sob controle da IaC ou que foram alterados por algum motivo.

Neste artigo, vamos mostrar como o Snyk IaC ajuda desenvolvedores a descobrir recursos em nuvem que não estão sob controle de infraestrutura como código (IaC) (recursos não gerenciados) ou que se desviaram do estado esperado (recursos gerenciados).

Configure o ambiente

O Snyk IaC lista os recursos encontrados como recursos do Terraform, para que você identifique facilmente qual parte do serviço de nuvem foi detectada. Por exemplo, um único serviço do Amazon API Gateway v2 é composto por pelo menos 12 recursos do Terraform. Com as informações de descoberta fornecidas pelo Snyk, você poderá decidir rapidamente se deve reverter a alteração, importar um novo recurso ou simplesmente excluir essa nova mudança.

Para acompanhar o passo a passo, você pode usar o arquivo Terraform abaixo para criar dois recursos da AWS que usaremos. Ele cria um usuário do IAM chamado "user1" com um sufixo aleatório, uma chave de acesso e uma política anexada com acesso somente leitura.

No momento da redação deste artigo, usamos o Terraform v1.1.7 com o provedor AWS v3.74.2

Reutilize a seguinte configuração HCL:

main.tf

resource "random_string" "prefix" {
  length  = 6
  upper   = false
  special = false
}

resource "aws_iam_user" "user1" {
  name = "user1-${random_string.prefix.result}"

  tags = {
    Name = "user1-${random_string.prefix.result}"
    manual = "true"
  }
}

resource "aws_iam_access_key" "user1" {
  user = aws_iam_user.user1.name
}

resource "aws_iam_user_policy_attachment" "user1" {
  user       = aws_iam_user.user1.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

Aplique essa configuração do Terraform:

$ terraform init
[...]
$ terraform apply
[...]

Confirme se há um terraform.tfstate na raiz do diretório:

$ ls -al terraform.tfstate
-rw-r--r--  1 sjourdan  staff  5049 Mar 16 18:31 terraform.tfstate

Confirme também se o usuário do IAM foi criado com sucesso na AWS.

Comece com o ambiente limpo

Vamos começar listando todos os recursos em nuvem que não estão sob controle do Terraform:

$ snyk iac describe --only-unmanaged

É provável que você encontre uma enorme lista de recursos que não estão sob controle do Terraform. São informações úteis, mas não muito práticas para o nosso caso. O Snyk IaC tem um recurso integrado para ignorar recursos em massa, adicionando todos os recursos encontrados ao arquivo de políticas .snyk.

Vamos ignorar todos esses recursos não gerenciados existentes, para trabalhar com mais precisão em um ambiente controlado, apenas com os dois recursos que criamos acima:

$ snyk iac describe --only-unmanaged --json  | snyk iac update-exclude-policy

Faça outra varredura para confirmar que o ambiente está ignorando os drifts detectados (mais tarde, você terá tempo de sobra para programar a importação deles).

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found 3 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

Agora podemos começar com o ambiente limpo.

Vamos criar drift no IAM!

Agora vamos criar três tipos de drift para simular situações reais:

  1. Uma alteração no usuário do IAM existente (que vamos querer reverter)

  2. A anexação manual de uma nova política do IAM (que vamos querer remover)

  3. Um novo usuário do IAM (que vamos querer aprimorar)

Para isso, acesse o console da AWS para IAM.

Altere o usuário do IAM existente adicionando uma tag

  1. Na página de usuários do IAM, clique em "user1"

  2. Clique na guia Tags

  3. Clique no botão Edit Tags

  4. Adicione uma nova chave ("environment") e um novo valor ("production")

  5. Clique em Salvar

Anexe uma política poderosa ao usuário do IAM existente

  1. Na página de usuários do IAM, clique em "user1"

  2. Clique na guia Permissions

  3. Clique no botão Adicionar permissões

  4. Clique em Attach existing policies directly

  5. Selecione Administrator Access

  6. Clique em Next: Review

  7. Confirme clicando em Add permissions

Crie manualmente outro usuário do IAM

  1. Na página de usuários do IAM, clique no botão Add Users

  2. Digite "user2" no campo User name:

  3. Selecione Access key

  4. Clique no botão Next: Permissions

  5. Não defina permissões nem tags

  6. Clique em Create user (não precisamos das credenciais exibidas, então você pode descartá-las).

Agora estamos prontos para lidar com esses tipos de alterações manuais usando a detecção de drift do Snyk IaC.

Drift na infraestrutura gerenciada e não gerenciada

Agora vamos descobrir como o Snyk IaC detecta essas alterações, começando pelos recursos que não são gerenciados pelo Terraform.

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_policy_attachment:
    - user1-84i30k-arn:aws:iam::aws:policy/AdministratorAccess
  aws_iam_user:
    - user2
Found 6 resource(s)
 - 50% coverage
 - 3 resource(s) managed by Terraform
 - 3 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

Esta varredura relatou, usando a terminologia de recursos do Terraform:

  • O usuário do IAM "user2" criado manualmente, com sua chave de acesso do IAM

  • A política do IAM anexada manualmente ao usuário do IAM "user1", gerenciado pelo Terraform.

Agora vamos verificar apenas as alterações nos recursos gerenciados pelo Terraform encontrados nos diferentes estados do Terraform:

$ snyk iac describe –only-managed
Scanned states (1)
Found changed resources:
  From tfstate://terraform.tfstate
    - user1-84i30k (aws_iam_user.user1):
        + tags.environment: <nil> => "production"
Found 5 resource(s)
 - 100% coverage
 - 5 resource(s) managed by Terraform
     - 1/5 resource(s) out of sync with Terraform state
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

Esta varredura apresentou um resultado bem diferente e levou muito mais tempo (36 s contra 9 s no modo de varredura de recursos "não gerenciados").

Com esse resultado, sabemos que o usuário do IAM chamado "user1-84i30k", que encontramos no HCL como um recurso chamado "user1", tem uma tag chamada "environment" definida como "production".

Plano de ação

A ferramenta de detecção de drift do Snyk nos ajudou a descobrir quatro diferenças inesperadas entre o que esperávamos e a realidade. Para este artigo, vamos supor que a equipe decida o seguinte:

  • O usuário do IAM "user2" é usado em produção e deve ser importado para o Terraform.

  • A chave de acesso do IAM de "user2" deve ser rotacionada por motivos de segurança.

  • Em hipótese alguma "user1" deve ter permissões de administrador.

  • A nova tag de "user1" é necessária para atender a um requisito e deve ser importada para o Terraform.

O que

Tipo de recurso

Nome

Tipo de drift

Ação

Um usuário do IAM

aws_iam_user

user2

Não gerenciado

IMPORTAR

Uma chave de acesso do IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

Não gerenciado

ROTACIONAR

Uma política do IAM anexada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

Não gerenciado

EXCLUIR

Uma tag em um usuário do IAM

aws_iam_user

tags.environment

Gerenciado

IMPORTAR

Pipelines de implantação não são uma solução

Temos um ótimo pipeline de implantação do Terraform. Quando o terraform apply for executado novamente, podemos esperar que tudo volte ao normal.

Nesse caso, o que o Terraform fará? Um trabalho de implantação:

$ terraform apply
Terraform will perform the following actions:

  # aws_iam_user.user1 will be updated in-place
  ~ resource "aws_iam_user" "user1" {
        id            = "user1-84i30k"
        name          = "user1-84i30k"
      ~ tags          = {
          - "environment" = "production" -> null
            # (1 unchanged element hidden)
        }
[...]

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

O Terraform nunca foi feito para descobrir recursos criados ou anexados manualmente e simplesmente reverterá os recursos modificados ao estado original (o que não queremos nesta situação).

O que

Tipo de recurso

Nome

Tipo de drift

Ação

Um usuário do IAM

aws_iam_user

user2

Não gerenciado

NENHUMA

Uma chave de acesso do IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

Não gerenciado

NENHUMA

Uma política do IAM anexada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

Não gerenciado

NENHUMA

Uma tag em um usuário do IAM

aws_iam_user

tags.environment

Gerenciado

REVERTER

Em nenhum dos casos recebemos a ajuda que esperamos:

  • O usuário do IAM criado manualmente e sua chave de acesso não são informados (pouco útil)

  • A política Administrator anexada manualmente a um usuário gerenciado não é informada (pouco útil)

  • A tag importante adicionada manualmente a um usuário gerenciado será revertida (prejudicial)

É necessária uma ferramenta diferente para esse tipo de detecção e trabalho.

Ampliando nossa cobertura

Começamos nossa jornada com 50% de cobertura dos recursos não gerenciados:

$ snyk iac describe --only-unmanaged

Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_policy_attachment:
    - user1-84i30k-arn:aws:iam::aws:policy/AdministratorAccess
  aws_iam_user:
    - user2
Found 6 resource(s)
 - 50% coverage
 - 3 resource(s) managed by Terraform
 - 3 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider

Vamos melhorar esse índice com base no plano da equipe.

Exclua a política do IAM de 'user1'

Vamos começar pelo mais urgente e fácil: remover a política "Administrator" do usuário do IAM gerenciado "user1":

  • Acesse IAM > Users > "user1"

  • Clique em Permissions > exclua "AdministratorAccess"

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
  aws_iam_user:
    - user2
Found 5 resource(s)
 - 60% coverage
 - 3 resource(s) managed by Terraform
 - 2 resource(s) not managed by Terraform

Agora cobrimos 60% dos nossos recursos da AWS, acima dos 50%.

O que

Tipo de recurso

Nome

Tipo de drift

Ação

Status

Um usuário do IAM

aws_iam_user

user2

Não gerenciado

IMPORTAR

Uma chave de acesso do IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

Não gerenciado

ROTACIONAR

Uma política do IAM anexada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

Não gerenciado

EXCLUIR

*

Uma tag em um usuário do IAM

aws_iam_user

tags.environment

Gerenciado

ADICIONAR

Vamos continuar.

Desbloqueie o pipeline de implantação do Terraform

O pipeline está bloqueado no momento por essa alteração manual nas tags de aws_iam_user.user1. Se houver uma implantação, as tags serão revertidas para o que está definido no HCL. Qual é a solução? Usar o resultado de drift do Snyk IaC para adaptar nossa configuração do Terraform.

Temos as seguintes informações:

Found changed resources:
  From tfstate://terraform.tfstate
    - user1-84i30k (aws_iam_user.user1):
        + tags.environment: <nil> => "production"

Com esse resultado, sabemos que:

  • Estamos procurando um recurso aws_iam_user chamado "user1"

  • Esse recurso está em terraform.tfstate (muito útil quando você tem dezenas ou centenas de estados)

  • Há uma nova chave de tag chamada environment com o valor "production".

Vamos atualizar o recurso de usuário do IAM simplesmente adicionando environment = "production", para que fique assim:

resource "aws_iam_user" "user1" {
 name = "user1-${random_string.prefix.result}"

 tags = {
   Name = "user1-${random_string.prefix.result}"
   environment = "production"
 }
}

Agora podemos desbloquear o pipeline de implantação do Terraform com segurança:

$ terraform apply
No changes. Your infrastructure matches the configuration.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Por enquanto, corrigimos nossos drifts "gerenciados":

$ snyk iac describe --only-managed
Scanned states (1)
Found 3 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

O que

Tipo de recurso

Nome

Tipo de drift

Ação

Status

Um usuário do IAM

aws_iam_user

user2

Não gerenciado

IMPORTAR

Uma chave de acesso do IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

Não gerenciado

ROTACIONAR

Uma política do IAM anexada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

Não gerenciado

EXCLUIR

*

Uma tag em um usuário do IAM

aws_iam_user

tags.environment

Gerenciado

ADICIONAR

*

Importe e rotacione user2 do IAM

Agora vamos lidar com o caso de "user2". Queremos:

  • Importá-lo para o Terraform

  • Rotacionar a chave

Vamos começar importando o usuário do IAM para o Terraform. Veja uma maneira simples de fazer isso.

Comece coletando as informações do Snyk IaC:

Tipo de recurso

Nome

aws_iam_user

user2

Como importar um aws_iam_user resource? De acordo com a documentação oficial do Terraform, os usuários do IAM podem ser importados usando o nome, por exemplo: $ terraform import aws_iam_user.lb loadbalancer.

Também podemos ver que o único argumento obrigatório é name. Então vamos adicionar essa estrutura básica ao nosso arquivo HCL:

resource "aws_iam_user" "user2" {
 name = "user2" # required
}

Agora vamos importar esse usuário para o Terraform:

$ terraform import aws_iam_user.user2 user2
aws_iam_user.user2: Importing from ID "user2"...
aws_iam_user.user2: Import prepared!
  Prepared aws_iam_user for import
aws_iam_user.user2: Refreshing state... [id=user2]

Import successful!

Como nossa cobertura evoluiu? Vamos descobrir:

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found resources not covered by IaC:
  aws_iam_access_key:
    - AKIASBXWQ3AYQETE6OFR
        User: user2
Found 5 resource(s)
 - 80% coverage
 - 4 resource(s) managed by Terraform
 - 1 resource(s) not managed by Terraform

Agora temos 80% de cobertura (antes, 60%) e resta apenas um recurso.

O que

Tipo de recurso

Nome

Tipo de drift

Ação

Status

Um usuário do IAM

aws_iam_user

user2

Não gerenciado

IMPORTAR

*

Uma chave de acesso do IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

Não gerenciado

ROTACIONAR

Uma política do IAM anexada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

Não gerenciado

EXCLUIR

*

Uma tag em um usuário do IAM

aws_iam_user

tags.environment

Gerenciado

ADICIONAR

*

Rotacione a chave

Vamos resolver isso agora. Queremos rotacionar a chave e adicioná-la ao Terraform. Primeiro, vamos adicionar a nova chave ao HCL para criar uma chave nova (que podemos fornecer à equipe relevante, por exemplo) e, por fim, simplesmente excluir a antiga da AWS.

A documentação do Terraform para aws_iam_access_key é bem clara, então podemos simplesmente criar um recurso que receba o nome de user2 como argumento:

resource "aws_iam_access_key" "user2" {
 user = aws_iam_user.user2.name
}

Como o pipeline de implantação já foi desbloqueado, podemos aplicar isso com segurança usando o Terraform para criar uma nova chave:

$ terraform apply 
[...]
Terraform will perform the following actions:

  # aws_iam_access_key.user2 will be created
  + resource "aws_iam_access_key" "user2" {
      + create_date          = (known after apply)
      + encrypted_secret     = (known after apply)
      + id                   = (known after apply)
      + key_fingerprint      = (known after apply)
      + secret               = (sensitive value)
      + ses_smtp_password_v4 = (sensitive value)
      + status               = "Active"
      + user                 = "user2"
    }

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

aws_iam_access_key.user2: Creating...
aws_iam_access_key.user2: Creation complete after 1s [id=AKIASBXWQ3AY4KPUNIHZ]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Ainda precisamos remover a chave antiga. Com as informações do resultado do Snyk IaC, sabemos que o nome da chave é AKIASBXWQ3AYQETE6OFR.

A maneira mais simples de remover essa chave é:

  • Acesse IAM > Users > user2 > Security Credentials

  • Remova a chave chamada AKIASBXWQ3AYQETE6OFR, indicada pelo Snyk IaC, desativando-a e, em seguida, excluindo-a.

Como está nossa cobertura agora?

$ snyk iac describe --only-unmanaged
Scanned states (1)
Found 5 resource(s)
 - 100% coverage
Congrats! Your infrastructure is fully in sync.

Parabéns! Tudo voltou a ficar sob controle graças à detecção de drift do Snyk IaC!

O que

Tipo de recurso

Nome

Tipo de drift

Ação

Status

Um usuário do IAM

aws_iam_user

user2

Não gerenciado

IMPORTAR

*

Uma chave de acesso do IAM

aws_iam_access_key

AKIASBXWQ3AYQETE6OFR

Não gerenciado

ROTACIONAR

*

Uma política do IAM anexada

aws_iam_policy_attachment

arn:aws:iam::aws:policy/AdministratorAccess

Não gerenciado

EXCLUIR

*

Uma tag em um usuário do IAM

aws_iam_user

tags.environment

Gerenciado

ADICIONAR

*

Para concluir

Neste artigo, mostramos como a detecção de drift do Snyk IaC ajuda a descobrir recursos da AWS criados manualmente e como ela apresenta tudo na terminologia do Terraform, com as informações certas para ajudar desenvolvedores a importar esses recursos para o código HCL do Terraform. Também vimos brevemente que reverter alterações automaticamente nem sempre é a melhor solução e que é preciso usar um sistema leve de alertas de detecção de drift junto com o pipeline de implantação.

Acreditamos firmemente que toda a infraestrutura deve estar representada em código, para que profissionais de engenharia tenham visibilidade e feedback de segurança sobre os problemas o quanto antes.

Por isso, o Snyk IaC ajuda as equipes a reintegrar rapidamente no código do Terraform todos os recursos que estão realmente em execução na conta da AWS, aumentando a cobertura geral de IaC e reduzindo os problemas de segurança. O Snyk IaC agiliza as correções ao fechar o ciclo de feedback entre as equipes de segurança em nuvem e engenharia, além de encaminhar aos engenheiros correções práticas, em uma linguagem que eles entendem.

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.