O terraform é uma ferramenta fantástica para provisionar e manter o estado de uma infraestrutura, tanto on-premises quanto nos ambientes de cloud. Entretanto, algumas vezes passamos por algumas situações que nós temos uma expectativa de que o terraform funcione de uma maneira, porém o terraform acaba funcionando de outra forma.
Foi o que aconteceu comigo ao utilizar o recurso aws_security_group. Este recurso permite criar um Security Group dentro de uma VPC, que na prática pode ser aplicado a outros recursos, como instâncias EC2, banco de dados, clusters Kubernetes, para fechar portas de conexão e liberar apenas algumas portas específicas (ou nenhuma).
Meu caso de uso foi criar um Security Group para uma instância EC2 que iria trabalhar como um worker, ou seja, essa instância iria obter os jobs através de uma fonte externa, realizar o processamento e enviar o resultado. Em resumo, por trabalhar em pull-based, essa instância não precisaria ter nenhuma regra de ingresso (entrada), apenas uma regra de egresso (saída) para qualquer IP.
Logo, fiz o recurso da seguinte maneira:
resource "aws_security_group" "sg" {
name = "my-amazing-security-group"
vpc_id = aws_vpc.main.id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Ao executar o comando terraform apply, obtive a seguinte saída:
gabriel@machine:~/terraform$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_security_group.sg will be created
+ resource "aws_security_group" "sg" {
+ arn = (known after apply)
+ description = "Managed by Terraform"
+ egress = [
+ {
+ cidr_blocks = [
+ "0.0.0.0/0",
]
+ description = ""
+ from_port = 0
+ ipv6_cidr_blocks = []
+ prefix_list_ids = []
+ protocol = "-1"
+ security_groups = []
+ self = false
+ to_port = 0
},
]
+ id = (known after apply)
+ ingress = (known after apply)
+ name = "my-amazing-security-group"
+ name_prefix = (known after apply)
+ owner_id = (known after apply)
+ revoke_rules_on_delete = false
+ tags_all = (known after apply)
+ vpc_id = "vpc-0101010101"
}
Plan: 1 to add, 0 to change, 0 to destroy.
aws_security_group.sg: Creating...
aws_security_group.sg: Creation complete after 2s [id=sg-0101010101010101]
Ótimo! O terraform criou o security group e eu pude utilizar na instância EC2 que criei. Entretanto, percebi que tinha cometido um erro ao provisionar a instância EC2 e eu precisava me conectar nessa instância usando ssh.
Para possibilitar o acesso, eu precisava criar a regra de ingresso no security group. Logo, fui diretamente no dashboard da AWS, editei o security group manualmente liberando a porta 22 para apenas o meu IP.
Após me conectar na instância e resolver o problema, pensei: “Vou simplesmente executar terraform apply, pois o terraform irá perceber a regra extra no security group e criar um plano para remover esta regra”. Então, ao executar o comando, obtive a seguinte saída:
gabriel@machine:~/terraform$ terraform apply
aws_security_group.sg: Refreshing state... [id=sg-0101010101010101]
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.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Na hora fiquei confuso. O terraform não percebeu a regra nova no security group? Fui no dashboard da AWS e vi que a regra de ingresso ainda estava presente! E agora?
Pesquisando melhor, entendi que o recurso aws_security_group não mantém o estado das regras, se isso não for explícito. Ou seja, precisamos deixar explícito na definição do recurso que não queremos nenhuma regra de ingresso. Corrigindo nosso código, ficaria assim:
resource "aws_security_group" "sg" {
name = "my-amazing-security-group"
vpc_id = data.aws_vpc.main.id
ingress = [] # explicitamente nenhuma regra de ingresso
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Perceba que o atributo ingress recebe uma lista vazia. Isto deixa explícito que não queremos nenhuma regra de ingresso para este security group. Logo, executando o comando terraform apply novamente, finalmente podemos ter o estado garantido:
gabriel@machine:~/terraform$ terraform apply
aws_security_group.sg: Refreshing state... [id=sg-0110522c7ec4870d0]
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_security_group.sg will be updated in-place
~ resource "aws_security_group" "sg" {
id = "sg-0110522c7ec4870d0"
~ ingress = [
- {
- cidr_blocks = [
- "169.169.169.169/32",
]
- description = "My IP"
- from_port = 22
- ipv6_cidr_blocks = []
- prefix_list_ids = []
- protocol = "tcp"
- security_groups = []
- self = false
- to_port = 22
},
]
name = "my-amazing-security-group"
tags = {}
# (7 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
aws_security_group.sg: Modifying... [id=sg-0110522c7ec4870d0]
aws_security_group.sg: Modifications complete after 0s [id=sg-0110522c7ec4870d0]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Ufa! Agora sim o terraform nos garante que este security group não ganhe novas regras através do dashboard da AWS e mantenha este estado pra gente.
Top comments (1)
A AWS é cheia de detalhezinho assim, né? Valeu por compartilhar!