DEV Community

Stefano Martins
Stefano Martins

Posted on • Updated on

Armazenando dados sensíveis em código Terraform utilizando KMS

Tratando-se de IaC, chegará cedo ou tarde o fatídico dia em que você terá que colocar uma senha, chave, ou qualquer outro dado sigiloso no seu código. Algumas pessoas não se preocupam muito quando estão versionando seus projetos, levando em consideração coisas como o fato de seus repositórios serem privados, por exemplo. Entretanto, sejamos sinceros: não há lá muita garantia que o código fique só no seu repositório, não é?

A grande maioria das ferramentas hoje conta com pelo menos um mecanismo para resolver esse pequeno probleminha. O Ansible, por exemplo, conta com o Ansible Vault. Já o Terraform conta com vários, como por exemplo a integração com o Vault (também da Hashicorp).

Neste breve artigo demonstrarei como manter seus dados seguros utilizando o AWS KMS (Key Management Service), serviço da AWS utilizado para criação e armazenamento de chaves e criptografia que conta com 20.000 requisições gratuitas no free tier e que pode ser utilizado entre múltiplos serviços. Bora lá?

O primeiro passo é a criação de uma chave dentro do KMS, que pode ser feita por meio do próprio Terraform ou através da Console. Caso opte pela primeira opção, serão necessários três tipos diferentes de objetos Terraform: um data source (aws_iam_policy_document) e dois resources (aws_kms_key e aws_kms_alias). Abaixo uma breve descrição do papel que cada um desempenhará:

  • aws_iam_policy_document: este é o data source onde definiremos o documento da política informando usuários e suas respectivas permissões referentes às chaves e recursos dentro do KMS.

Detalhe: aqui nós estamos utilizando uma policy do tipo resource-based.

  • aws_kms_key: a chave propriamente dita. Aqui informaremos o tipo da chave, se ela é simétrica ou assimétrica, se ela pode ser utilizada para criptografar ou descriptografar, assim como associar o documento criado no data source para definir uma política de acesso à ela';

  • aws_kms_alias: um alias nada mais é do que um apelido utilizado para referenciar a chave.

Abaixo o código Terraform:

data "aws_iam_policy_document" "how_to_terraform_kms_pd" {
  statement {
    sid = "Enable IAM User Permissions"
    effect = "Allow"
    principals {
      type = "AWS"
      identifiers = [
        "arn:aws:iam::111111111111:root"
      ]
    }
    actions = [
      "kms:*"
    ]
    resources = [
      "*"
    ]
  }

  statement {
    sid = "Allow use of the key"
    effect = "Allow"
    principals {
      type = "AWS"
      identifiers = [
        "arn:aws:iam::111111111111:user/meu-usuario"
      ]
    }
    actions = [
      "kms:Encrypt",
      "kms:Decrypt",
      "kms:ReEncrypt*",
      "kms:GenerateDataKey*",
      "kms:DescribeKey"
    ]
    resources = [
      "*"
    ]
  }

  statement {
    sid = "Allow attachment of persistent resources"
    principals {
      type = "AWS"
      identifiers = [
        "arn:aws:iam::111111111111:user/meu-usuario"
      ]
    }
    actions = [
      "kms:CreateGrant",
      "kms:ListGrants",
      "kms:RevokeGrant"
    ]
    resources = [
      "*"
    ]
    condition {
      test = "Bool"
      variable = "kms:GrantIsForAWSResource"
      values = [
        "true"
      ]
    }
  }
}

resource "aws_kms_key" "how_to_terraform_kms" {
  description = "Teste de criptografia com KMS"
  key_usage = "ENCRYPT_DECRYPT"
  customer_master_key_spec = "SYMMETRIC_DEFAULT"
  policy = data.aws_iam_policy_document.how_to_terraform_kms_pd.json
}

resource "aws_kms_alias" "how_to_terraform_kms_alias" {
  name = "alias/how_to_terraform_kms"
  target_key_id = aws_kms_key.how_to_terraform_kms.key_id
}

output "how_to_terraform_kms_id" {
  value = aws_kms_key.how_to_terraform_kms.key_id
}
Enter fullscreen mode Exit fullscreen mode

Nota: no data source how_to_terraform_kms_pd, nós definimos o account ID como 111111111111 e o usuário como meu-usuario. Ajuste esses valores para o seu caso.

Após um terraform plan e um terraform apply os recursos já devem estar presentes na sua conta AWS. Note que há também um output que imprime o ID da chave recém-criada e caso você opte por consultá-lo diretamente na Console, o mesmo pode ser removido.

Com a chave pronta para uso, agora é hora de criptografar algo. E é aí que o nosso velho amigo AWS CLI entra em cena. Utilize para isso o seguinte comando:

aws kms encrypt --key-id ${key_id} \ 
  --plaintext ${texto_a_ser_criptografado} \
  --output text \
  --query CiphertextBlob
Enter fullscreen mode Exit fullscreen mode

Nota: não se esqueça que você deve ter exportado as variáveis como AWS_SECRET_ACCESS_KEY e AWS_ACCESS_KEY_ID corretamente no seu terminal para acessar sua conta.

Se tudo der certo, o valor criptografado deve aparecer na tela.

Neste momento você deve estar se perguntando "OK, mas o propósito não era esconder as coisas no código do Terraform?". Estamos chegando lá. Este valor criptografado que nós geramos utilizando o AWS CLI pode ser resgatado dentro do próprio Terraform, que consulta o KMS durante sua execução utilizando o data source aws_kms_secrets da seguinte forma:

data "aws_kms_secrets" "teste_kms" {
  secret {
    name = "valor_resgatado"
    payload = "AQICAHhAVXI4s1jnWVzWUxKnuk9yI2/aDoEQu8vyYkhh0tUC2QEMKXf54sQFje6ImNjDyraEAAAAcjBwBgkqhkiG9w0BBwagYzBhAgEAMFwGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMoKPEjuATAOXqrzraAgEQgC9Kwf2DiUTxrDy0g8kggiLc+bhWhuYLDQaB/DhsMxyV9pD6ROsT/boZztyJFD30oQ=="
  }
}

output "valor_resgatado" {
  value = data.aws_kms_secrets.teste_kms.plaintext["valor_resgatado"]
}
Enter fullscreen mode Exit fullscreen mode

Dentro do bloco secret do data source você deve dar um nome único para referenciá-lo e o seu valor criptográfico. Não é necessário informar a chave, uma vez que ela já está contida no payload. Você pode então referenciar o secret em qualquer parte do seu código utilizando a notação data.aws_kms_secrets.teste_kms.plaintext["valor_resgatado"]. Você pode incluir quantos blocos secret quiser dentro do data source.

Referências

Oldest comments (0)