자 저번에 VPC까지 만들었으니 이제 보안규칙과 EC2를 만들어 보겠습니다!
Security groups and network ACLs are similar in that they allow you to control access to AWS resources within your VPC. But security groups allow you to control inbound and outbound traffic at the instance level, while network ACLs offer similar capabilities at the VPC subnet level. There is no additional charge for using security groups or network ACLs.
참고로 만들기 전에 security group 과 network acl의 차이점이라고 합니다(https://docs.aws.amazon.com/whitepapers/latest/aws-best-practices-ddos-resiliency/security-groups-and-network-acls-bp5.html)
security group은 inbound, outbound traffic at instance level이라고 하고
network acl은 vpc subnet level에서 이루어진다고 한다.
먼저 Security group 을 만들어준다
resource "aws_default_security_group" "meme_vpc_default" {
vpc_id = aws_vpc.side_effect.id
ingress {
protocol = -1
self = true
from_port = 0
to_port = 0
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "security by terraform"
}
}
=> manage the default security group of the default or a non-default VPC.
=> When Terraform first begins managing the default security group, it immediately removes all ingress and egress rules in the Security Group. It then creates any rules specified in the configuration. This way only the rules specified in the configuration are created.
-> 테라폼은 시작을할때 모든 ingress, egress rules를 지워버린다고해서 새롭게 ingress와 egress를 설정해주어야 한다. 나는 모두 열어두었다.
=> aws_default_security_group 말고 aws_security_group를 사용해도 상관은 없다. 그저 기본 보안그룹을 사용하느냐 새롭게 만드느냐 그차이일 뿐이다.
그런다음은 각 서브넷의 acl을 설정할 network_acl을 설정할 차례이다. vpc와 연결된 기본 network acl을 가져와 다음과 같이 초기화 해준다.
resource "aws_default_network_acl" "meme_vpc_default" {
default_network_acl_id = aws_vpc.meme_vpc.default_network_acl_id
ingress {
protocol = -1
rule_no = 100
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 0
to_port = 0
}
egress {
protocol = -1
rule_no = 100
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 0
to_port = 0
}
tags = {
Name = "default network acl"
}
}
이렇게 기본 network_acl을 초기화 해준다음에 network acl을 어떤 subnet에 적용할것인지 설정해준다
resource "aws_network_acl" "meme_vpc_public" {
vpc_id = aws_vpc.meme_vpc.id
subnet_ids = [
aws_subnet.meme_vpc_public_subnet1.id,
aws_subnet.meme_vpc_public_subnet2.id,
]
tags = {
Name = "public"
}
}
=> subnet_ids - (Optional) A list of Subnet IDs to apply the ACL to
그럼 다음 세부적인 rule을 추가해준다
=> Creates an entry (a rule) in a network ACL with the specified rule number.
resource "aws_network_acl_rule" "meme_vpc_public_ingress80" {
network_acl_id = aws_network_acl.meme_vpc_public.id
rule_number = 100
rule_action = "allow"
egress = false
protocol = "tcp"
cidr_block = "0.0.0.0/0"
from_port = 80
to_port = 80
}
resource "aws_network_acl_rule" "meme_vpc_public_egress80" {
network_acl_id = aws_network_acl.meme_vpc_public.id
rule_number = 100
rule_action = "allow"
egress = true
protocol = "tcp"
cidr_block = "0.0.0.0/0"
from_port = 80
to_port = 80
}
이 그림과 같이 적용해야하는 모든 것을 적어준다.
network_acl_id - (Required) The ID of the network ACL.
rule_number - (Required) The rule number for the entr
y (for example, 100). ACL entries are processed in ascending order by rule number.
egress - (Optional, bool) Indicates whether this is an egress rule (rule is applied to traffic leaving the subnet). Default false.
protocol - (Required) The protocol. A value of -1 means all protocols.
rule_action - (Required) Indicates whether to allow or deny the traffic that matches the rule. Accepted values: allow | deny
cidr_block - (Optional) The network range to allow or deny, in CIDR notation (for example 172.16.0.0/24 ).
ipv6_cidr_block - (Optional) The IPv6 CIDR block to allow or deny.
from_port - (Optional) The from port to match.
to_port - (Optional) The to port to match.
icmp_type - (Optional) ICMP protocol: The ICMP type. Required if specifying ICMP for the protocolE.g., -1
icmp_code - (Optional) ICMP protocol: The ICMP code. Required if specifying ICMP for the protocolE.g., -1
저는 위와 같이 80, 443, 22, (1024~65535), 8080, 5439, 3306을 모두 뚫어주었습니다.
또한 public 과 private을 나누어서 함으로써 보안을 추가했습니다.
또한 bastion host를 만들기 위해서 bastion 호스트를 위한 보안 규칙을 따로 만들었습니다
// Basiton Host
resource "aws_security_group" "meme_vpc_bastion" {
name = "meme_security"
description = "Security group for bastion instance"
vpc_id = aws_vpc.meme_vpc.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 5439
to_port = 5439
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "ec2_security"
}
}
이런식으로 보안규칙을 다 만들고 나서는 EC2를 만들어 주었습니다.
resource "aws_instance" "meme_service_ec2" {
ami = "ami-0f3a440bbcff3d043"
availability_zone = aws_subnet.meme_vpc_public_subnet1.availability_zone
instance_type = "t2.micro"
key_name = aws_key_pair.terraform-key-pair.key_name
vpc_security_group_ids = [
aws_default_security_group.meme_vpc_default.id,
]
subnet_id = aws_subnet.meme_vpc_public_subnet1.id
associate_public_ip_address = true
tags = {
Name = "meme_service_ec2"
}
}
ami - ID of the AMI used to launch the instance.
arn - ARN of the instance.
associate_public_ip_address - Whether or not the Instance is associated with a public IP address or not (Boolean).
availability_zone - Availability zone of the Instance.
iam_instance_profile - Name of the instance profile associated with the Instance.
instance_type - Type of the Instance.
key_name - Key name of the Instance.
public_dns - Public DNS name assigned to the Instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC.
public_ip - Public IP address assigned to the Instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use
public_ip, as this field will change after the EIP is attached.
subnet_id - VPC subnet ID.
vpc_security_group_ids - Associated security groups in a non-default VPC.
하지만 여기서 key_name에서 인스턴스 접속을 위한 키가 필요합니다.
resource "aws_key_pair" "terraform-key-pair" {
# 등록할 key pair의 name
key_name = var.PUBLIC_KEY_NAME
# public_key = "{.pub 파일 내용}"
public_key = var.PUBLIC_KEY
tags = {
description = "terraform key pair import"
}
}
저는 직접 ssh-keygen을 이용해 publickey와 privatekey를 발급받았습니다.
$ ssh-keygen -t rsa -b 4096 -C "" -f "{저장하고자하는 경로}/tf-key-pair" -N ""
자세한 내용은 [출처 : https://devs0n.tistory.com/55] 를 참고해서 만드시면 됩니다!
그런다음 탄력적 ip를 연결하기 위해
resource "aws_eip" "meme_auth_ec2" {
instance = aws_instance.meme_auth_ec2.id
depends_on = ["aws_internet_gateway.meme_vpc_igw"]
}
의 코드를 써준다.
id - (Optional) Allocation ID of the specific VPC EIP to retrieve. If a classic EIP is required, do NOT set id, only set public_ip
association_id - ID representing the association of the address with an instance in a VPC.
domain - Whether the address is for use in EC2-Classic (standard) or in a VPC (vpc).
instance_id - ID of the instance that the address is associated with (if any).
이런식으로 설정을 하면 기본적인 EC2까지는 만들 수 있게 됩니다