CloudWatch Agent
를 EC2 인스턴스에 설치
하고 지표를 수집할 수 있도록 하는 전반적인 과정을 테라폼을 통해 자동화 해보았습니다.역할을 생성
합니다. 역할에는 CloudWatch agent와 ssm과 연관된 정책이 연결됩니다.네트워크 인프라를 구성
합니다. VPC, Subnet, IGW, Routing Table, Network Interface, Security Group 등이 있습니다.키 파일을 생성
하고 다운로드
받습니다.인스턴스를 생성
합니다. 인스턴스에는 역할, Network Interface, 키 파일, 프로비저닝 스크립트가 포함됩니다.역할을 생성
합니다. 역할은 EC2 서비스 용도이기 때문에 assume_role_policy
는 ec2
서비스에 대해서만 허용되어야 합니다.# ssm, cloudwatch agent를 허용하는 역할 생성
resource "aws_iam_role" "EC2InstacneToSSMandCloudwatchAgent" {
name = "test_EC2InstacneToSSMandCloudwatchAgent"
path = "/"
assume_role_policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Service" : "ec2.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}
]
}
)
}
인스턴스 프로파일
을 생성해야 합니다. aws_iam_instance_profile
리소스를 이용하면 됩니다.# 역할을 ec2 인스턴스에 연결하기 위해 인스턴스 프로파일 생성
resource "aws_iam_instance_profile" "ec2_profile" {
name = "ec2_profile"
role = aws_iam_role.EC2InstacneToSSMandCloudwatchAgent.name
}
ssm
을 허용하는 정책인 AmazonSSMManagedInstanceCore
를 불러와서 역할에 붙여줍니다.# ssm 접근 허용 정책(EC2 용)
data "aws_iam_policy" "AmazonSSMManagedInstanceCore" {
name = "AmazonSSMManagedInstanceCore"
}
resource "aws_iam_role_policy_attachment" "AmazonSSMManagedInstanceCore" {
role = aws_iam_role.EC2InstacneToSSMandCloudwatchAgent.name
policy_arn = data.aws_iam_policy.AmazonSSMManagedInstanceCore.arn
}
cloudwatch agent
을 허용하는 정책인 CloudWatchAgentServerPolicy
를 불러와서 역할에 붙여줍니다.# cloudwatch agent 허용 정책(EC2 용)
data "aws_iam_policy" "CloudWatchAgentServerPolicy" {
name = "CloudWatchAgentServerPolicy"
}
resource "aws_iam_role_policy_attachment" "CloudWatchAgentServerPolicy" {
role = aws_iam_role.EC2InstacneToSSMandCloudwatchAgent.name
policy_arn = data.aws_iam_policy.CloudWatchAgentServerPolicy.arn
}
# ssm, cloudwatch agent를 허용하는 역할 생성
resource "aws_iam_role" "EC2InstacneToSSMandCloudwatchAgent" {
name = "test_EC2InstacneToSSMandCloudwatchAgent"
path = "/"
assume_role_policy = jsonencode(
{
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Service" : "ec2.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}
]
}
)
}
# 역할을 ec2 인스턴스에 연결하기 위해 인스턴스 프로파일 생성
resource "aws_iam_instance_profile" "ec2_profile" {
name = "ec2_profile"
role = aws_iam_role.EC2InstacneToSSMandCloudwatchAgent.name
}
# ssm 접근 허용 정책(EC2 용)
data "aws_iam_policy" "AmazonSSMManagedInstanceCore" {
name = "AmazonSSMManagedInstanceCore"
}
resource "aws_iam_role_policy_attachment" "AmazonSSMManagedInstanceCore" {
role = aws_iam_role.EC2InstacneToSSMandCloudwatchAgent.name
policy_arn = data.aws_iam_policy.AmazonSSMManagedInstanceCore.arn
}
# cloudwatch agent 허용 정책(EC2 용)
data "aws_iam_policy" "CloudWatchAgentServerPolicy" {
name = "CloudWatchAgentServerPolicy"
}
resource "aws_iam_role_policy_attachment" "CloudWatchAgentServerPolicy" {
role = aws_iam_role.EC2InstacneToSSMandCloudwatchAgent.name
policy_arn = data.aws_iam_policy.CloudWatchAgentServerPolicy.arn
}
VPC
를 생성합니다. 여기서 enable_dns_hostnames
과 enable_dns_support
속성을 true
로 설정하면 이후 인스턴스를 이 VPC에 연결할 때 Public DNS
가 붙게 됩니다.# VPC 생성
resource "aws_vpc" "test_hyeob_vpc" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
# 인스턴스에 public DNS가 표시되도록 하는 속성
enable_dns_hostnames = true
enable_dns_support = true
tags = local.tags
}
서브넷
을 생성합니다. 서브넷은 VPC 내에 생성하고, cidr
와 가용 영역
을 설정해줍니다.# 서브넷 생성
resource "aws_subnet" "test_hyeob_subnet" {
vpc_id = aws_vpc.test_hyeob_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-2a"
tags = local.tags
}
인터넷 게이트웨이(IGW)
를 생성합니다. IGW는 VPC에 연결합니다.IGW
는 생성하면서 VPC에 연결하면 됩니다. 따로 attach
리소스를 이용할 필요는 없습니다.# 인터넷 게이트웨이 생성 후 VPC에 연결
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.test_hyeob_vpc.id
tags = local.tags
}
라우팅 테이블
을 생성하고 IGW
와 서브넷
에 연결합니다.# 라우팅 테이블 생성 후 igw에 연결
resource "aws_route_table" "rt" {
vpc_id = aws_vpc.test_hyeob_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
tags = local.tags
}
# 서브넷과 라우팅 테이블 연결
resource "aws_route_table_association" "rta" {
subnet_id = aws_subnet.test_hyeob_subnet.id
route_table_id = aws_route_table.rt.id
}
보안 그룹
을 생성합니다. 저는 22
, 80
포트의 인바운드를 허용하고, 모든 포트의 아웃바운드를 허용했습니다. 보안 그룹은 VPC에 연결해줍니다.resource "aws_security_group" "test_hyeob_sg" {
name = "test_hyeob_sg"
description = "Allow SSH inbound traffic"
vpc_id = aws_vpc.test_hyeob_vpc.id
# 인바운드: ingress
ingress {
description = "SSH from VPC"
# 포트 범위: from_port ~ to_port
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP"
# 포트 범위: from_port ~ to_port
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# 아웃바운드: egress
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = local.tags
}
네트워크 인터페이스
를 생성합니다. 원하는 정적 사설 IP를 지정할 수 있습니다. security_groups
속성에 보안 그룹을 입력해서 연결합니다. 이후 인스턴스에서 따로 vpc_security_group_ids
속성을 이용할 필요가 없고, network_interface
속성만 연결해주면 보안 그룹도 함께 연결
됩니다.resource "aws_network_interface" "ni" {
subnet_id = aws_subnet.test_hyeob_subnet.id
private_ips = ["10.0.1.10"]
security_groups = [aws_security_group.test_hyeob_sg.id]
tags = local.tags
}
# VPC 생성
resource "aws_vpc" "test_hyeob_vpc" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
# 인스턴스에 public DNS가 표시되도록 하는 속성
enable_dns_hostnames = true
enable_dns_support = true
tags = local.tags
}
# 서브넷 생성
resource "aws_subnet" "test_hyeob_subnet" {
vpc_id = aws_vpc.test_hyeob_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-2a"
tags = local.tags
}
# 인터넷 게이트웨이 생성 후 VPC에 연결
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.test_hyeob_vpc.id
tags = local.tags
}
# 라우팅 테이블 생성 후 igw에 연결
resource "aws_route_table" "rt" {
vpc_id = aws_vpc.test_hyeob_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
tags = local.tags
}
# 서브넷과 라우팅 테이블 연결
resource "aws_route_table_association" "rta" {
subnet_id = aws_subnet.test_hyeob_subnet.id
route_table_id = aws_route_table.rt.id
}
resource "aws_security_group" "test_hyeob_sg" {
name = "test_hyeob_sg"
description = "Allow SSH inbound traffic"
vpc_id = aws_vpc.test_hyeob_vpc.id
# 인바운드: ingress
ingress {
description = "SSH from VPC"
# 포트 범위: from_port ~ to_port
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP"
# 포트 범위: from_port ~ to_port
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# 아웃바운드: egress
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = local.tags
}
resource "aws_network_interface" "ni" {
subnet_id = aws_subnet.test_hyeob_subnet.id
private_ips = ["10.0.1.10"]
security_groups = [aws_security_group.test_hyeob_sg.id]
tags = local.tags
}
Harsicorp 자체 리소스
인 tls_private_key
를 이용하여 개인 키(private key)
를 생성합니다.# RSA 알고리즘을 이용해 private 키 생성.
resource "tls_private_key" "pk" {
algorithm = "RSA"
rsa_bits = 4096
}
private key
를 가지고 AWS
에서 키 페어
를 생성합니다.# private 키를 가지고 keypair 파일 생성.
resource "aws_key_pair" "kp" {
key_name = "test_hyeob_keypair"
public_key = tls_private_key.pk.public_key_openssh
}
Harsicorp 자체 리소스
인 local_file
을 이용해 .pem
키를 다운 받습니다.# 키 파일을 생성하고 로컬에 다운로드.
resource "local_file" "ssh_key" {
filename = "${aws_key_pair.kp.key_name}.pem"
content = tls_private_key.pk.private_key_pem
}
# RSA 알고리즘을 이용해 private 키 생성.
resource "tls_private_key" "pk" {
algorithm = "RSA"
rsa_bits = 4096
}
# private 키를 가지고 keypair 파일 생성.
resource "aws_key_pair" "kp" {
key_name = "test_hyeob_keypair"
public_key = tls_private_key.pk.public_key_openssh
}
# 키 파일을 생성하고 로컬에 다운로드.
resource "local_file" "ssh_key" {
filename = "${aws_key_pair.kp.key_name}.pem"
content = tls_private_key.pk.private_key_pem
}
amazon linux 2
이미지를 불러옵니다.# amazon linux 2 이미지 불러오기
data "aws_ami" "amazon-linux-2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-ebs"]
}
}
ec2 인스턴스
를 생성합니다. 불러온 이미지를 연결하고, 네트워크 인터페이스, 키 페어 파일을 연결합니다. user_data
에는 쉘 스크립트 파일
이 들어가는데, 인스턴스가 생성되고 Cloudwatch agent
의 설치부터 시작까지의 과정을 프로비저닝하는 코드가 들어있습니다.프로비저닝하는 쉘 스크립트 코드는 [AWS] CloudWatch Agent 설치부터 시작까지 스크립트로 자동화를 참고하세요.
vpc_security_group_ids
를 사용할 필요가 없습니다.resource "aws_instance" "test_hyeob_instance" {
ami = data.aws_ami.amazon-linux-2.id
instance_type = "t2.micro"
network_interface {
network_interface_id = aws_network_interface.ni.id
device_index = 0
}
# network_interface를 인스턴스에 붙이지 않는다면 아래 속성으로 보안 그룹을 붙여줍니다.
# vpc_security_group_ids = [aws_security_group.test_hyeob_sg.id]
# 역할(인스턴스 프로파일)을 붙여줍니다.
iam_instance_profile = aws_iam_instance_profile.ec2_profile.name
# 키 파일을 이용해 생성
key_name = aws_key_pair.kp.key_name
# cloudwatch agent 설치부터 구성 파일 생성, 데몬 시작까지 자동화 스크립트 실행
user_data = "${file("cloudwatch_agent.sh")}"
tags = local.tags
}
탄력적 IP
를 인스턴스에 붙여줍니다.# 탄력적 IP 붙여주기
resource "aws_eip" "lb" {
instance = aws_instance.test_hyeob_instance.id
vpc = true
}
# amazon linux 2 이미지 불러오기
data "aws_ami" "amazon-linux-2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-ebs"]
}
}
resource "aws_instance" "test_hyeob_instance" {
ami = data.aws_ami.amazon-linux-2.id
instance_type = "t2.micro"
network_interface {
network_interface_id = aws_network_interface.ni.id
device_index = 0
}
# network_interface를 인스턴스에 붙이지 않는다면 아래 속성으로 보안 그룹을 붙여줍니다.
# vpc_security_group_ids = [aws_security_group.test_hyeob_sg.id]
# 역할(인스턴스 프로파일)을 붙여줍니다.
iam_instance_profile = aws_iam_instance_profile.ec2_profile.name
# 키 파일을 이용해 생성
key_name = aws_key_pair.kp.key_name
# cloudwatch agent 설치부터 구성 파일 생성, 데몬 시작까지 자동화 스크립트 실행
user_data = "${file("cloudwatch_agent.sh")}"
tags = local.tags
}
# 탄력적 IP 붙여주기
resource "aws_eip" "lb" {
instance = aws_instance.test_hyeob_instance.id
vpc = true
}