
내년 초쯤 AWS 계정 분리 및 마이그레이션 관련으로 Terraform을 도입하게 되면서, Terraformer를 통해 이미 존재하는 AWS 리소스들을 Terraform 파일 및 상태 파일로 가져오는 작업을 진행했던 내용을 공유해본다.
요구사항은 간단했다. 이미 돌아가고 있는 환경의 리소스들을 최대한 동일한 설정으로 추출해서 Terraform 파일로 만드는 것이다.
하지만 수많은 리소스들을 콘솔을 확인해가면서 손수 파일을 하나하나 작성하는 것은 상당히 어려운 일이며 (이 과정에서 분명 다른 리전에 숨겨져있거나 만들어놓고 방치해둔 리소스들이 숨어 있을 수도 있음) 더욱이 서비스 별, 환경 별로도 따로 만들어야 했기 때문에 처음부터 하나하나 Terraform 파일을 만들어야 한다는 것을 생각해보면 막막할 따름이다.
그래서 이미 돌아가고 있는 AWS 환경의 리소스들을 Terraform 파일로 추출해주는 도구가 있는지 확인을 해봤는데, 정말 다행히도 Terraformer라는 것이 존재했다.
https://github.com/GoogleCloudPlatform/terraformer
Terraformer는 이미 존재하는 인프라를 기반으로 Terraform 파일, 상태 파일들을 생성해주는 CLI 도구이다. (reverse Terraform)
지원되는 Provider는 AWS, Azure, GCP와 같은 클라우드 뿐만 아니라 Terraform이 지원하는 Provider의 상당수를 지원해주고 있으며, 그 목록은 README에서 확인이 가능하다.
https://github.com/GoogleCloudPlatform/terraformer/blob/master/docs/aws.md
그 중에서 AWS 쪽에서 가져올 수 있는 리소스의 목록은 위의 aws.md에 존재하는데 굵직한 것들은 대부분 가져올 수 있는 것으로 확인된다.
비슷한 성격의 프로젝트인 Terraforming이 2022년부터 관리가 되지 않는 것과는 다르게 지금도 지속적으로 관리가 되고 있는 프로젝트이다.
먼저 사용하려는 Provider에 맞는 플러그인을 설치해주고, 시스템 환경 변수에 플러그인 설치 경로를 입력해줘야 한다.
여기서 플러그인 파일 이름을 terraformer로 해줘야 CLI에서 terraformer 명령어 인식이 가능하다.
이후, terraform 파일을 추출할 디렉터리에 providers.tf 를 작성한다
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
provider "aws" {
region = "ap-northeast-2"
}
이 상태에서 terraform init 을 한 후, AWS CLI를 통해 리소스에 접근 가능한 유저로 로그인을 한 상태에서 terraformer import aws resources=${리소스 종류} 로 import를 할 수 있다.
(terraformer import 관련 명령어는 README와 aws.md를 확인해보면 다양한 조건을 확인할 수 있다)
import된 리소스들은 보통 generated 디렉터리 하위에 리소스 종류별로 서브 디렉터리가 생기고, 그 안에 다양한 Terraform 파일과 변수 파일, 출력 파일들이 생성된다.
generated
ㄴ iam
ㄴ iam_user.tf
ㄴ ...
ㄴ outputs.tf
ㄴ vpc
ㄴ ...
이렇게 가져와야 할 리소스 종류만 알고 있다면 terraformer import 로 아주 간편하게 이미 구성되어 있는 리소스의 설정들이 담긴 Terraform 파일들이 출력된다.
하지만 이것만으로 바로 terraform plan, terraform apply 를 해서는 안되는데, 다음과 같은 유의사항이 있기 때문이다.
예를 들어 계정 내에 있는 모든 리소스를 가져와야 하는 것이라면 상관이 없겠지만 어느 리소스는 가져와야 하고 어떤 것은 가져오지 않아도 되는 것들이 있을텐데, 이에 대한 구분을 위해 이름이나 태깅을 해두는 것이 필요하다.
보통 리소스 이름이 prefix 기반으로 잘 정리가 되어 있다면 상관이 없겠지만 그렇지 않은 경우라면 태그를 사용하여 필터 조건에 태그를 넣어두면 좋을 것 같다. 물론, 모든 리소스가 태그를 쓸 수 있는 것은 아니라서 태그를 적용할 수 없는 리소스는 이름 조건이나 다른 것들로 가져와야 할 것이다.
# 태그 조건으로 필터링 예시
terraformer import aws resources=vpc,subnet --region=ap-norhteast-2 --filter="Name=tag.owner;Value=cocoball"
이미 구성되어 있는 리소스를 기반으로 Terraform 파일을 추출하는 것이기 때문에, 리소스 간 연관관계에 필요한 식별자 값 (arn, id, name 등...) 이 전부 하드코딩 되어 있다.
문제는 알아보기 쉬운 문자열 등으로 되어 있다면 그나마 다행인데, outputs.tf 으로 따로 빠져 있는 값을 참조하는 경우라면 일일이 이 리소스가 어떤 outputs.tf를 보고 있고 이 outputs.tf에 선언된 값은 어떤 리소스를 보고 있는지를 일일이 확인해야 한다.
확인이 끝났다면, outputs.tf가 아닌, Terraform 파일 내에 선언한 리소스를 참조하도록 변경해주어야 한다.
# 기존 (문자열로 하드코딩되어 있는 경우)
vpc_id = "dsfsdsdfsdfdsf"
# 변경 (실제 연결되어야 할 vpc 리소스 선언한 이후 참조)
vpc_id = aws_vpc.test_vpc.id
# 기존 (outputs.tf를 참조하고 있는 경우)
load_balancer_arn = "${data.terraform_remote_state.alb.outputs.aws_lb_tfer--test_alb_id}"
# 변경 (실제 연결되어야 할 로드밸런서 리소스 선언한 이후 참조)
load_balancer_arn = aws_lb.test_alb.arn
iam 리소스의 경우 deprecated된 속성이 제법 있었는데 (inline_policy → aws_iam_role_policy 로 변경한 후 iam_role_policy_attachment로 연결 / managed_policy_arns → aws_iam_role_policy_attachement 로 매핑) IDE에서 Terraform 관련 플러그인을 설치한다면 이러한 속성들을 볼 수 있다. 이 경우 공식 문서를 보면서 수정을 해줘야 한다.
Terraformer가 모든 리소스나 속성을 가져오는 것은 아닌데, 보통 비밀번호나 키와 같은 민감한 정보와 관련된 속성은 사용자가 직접 생성해서 SSM Parameter Store 등에 저장해두고 data로 가져오는 경우가 많았다.
그리고 아예 생성이 안 되는 리소스는 대표적으로 ECS 클러스터와 연관이 있는 용량 제공자 (aws_ecs_capacity_provider), CloudFront의 응답 헤더 정책(aws_cloudfront_response_headers_policy), OAC(aws_cloudfront_origin_access_control), 퍼블릭 키(aws_cloudfront_public_key), 키 그룹 (aws_cloudfront_key_group) 등이 있는데 이러한 것들은 Terraform 상태 파일에서 하드 코딩으로 참조되어 있는데 리소스가 빠져 있는 사실을 알게 된 이후 콘솔에서 정보를 보면서 직접 만들어줘야 한다.
위에 유의사항을 적어두긴 했지만, 이러한 것들만 잘 확인할 수 있다면 큰 수고를 들이지 않고 Terraform 파일로 만들 수 있다는 점이 정말 편리한 것 같다.
그리고 Terraformer를 통해 출력된 Terraform 파일들을 수정하면서 AWS 내에 존재하는 리소스들의 종류와 연관관계, 구조를 한 번 더 확인할 수 있었던 것 같다.
사실 Terraform 강의만 수강했을 때에는 지금 있는 리소스들을 어떻게 Terraform 파일로 만들어야 하나 고민이 많았었는데, 다행히 Terraformer를 통해 실제 리소스들을 대상으로 공부도 할 수 있었고, 마이그레이션 준비도 좀 더 수월하게 진행할 수 있었다.
만약 필자와 같은 상황에 있다면, Terraformer를 사용해보는 것을 추천한다.