나무 블록, 보안 방패, 구름 도형으로 멀티클라우드 모듈 표준화를 표현한 평면 이미지
글 요약
Terraform Module 설계 방법으로 FortiGate, AWS, Azure 멀티 클라우드 환경을 표준화하는 노하우를 담았습니다. Provider 추상화, 변수 계층화, 실패 사례 복기, 그리고 다른 IaC 도구와의 비교까지 한 번에 정리해 드립니다.
“FortiGate는 FortiGate대로, AWS는 AWS대로, Azure는 Azure대로 모듈을 짜니까 관리 포인트가 세 배가 됐어요.”
그 고민, 사실 거의 모든 멀티 클라우드 운영자가 한 번씩은 겪는 증상입니다. Terraform Module 설계를 Provider별로 분리하면서도 변수 인터페이스는 통일하면, 같은 코드로 세 클라우드를 한 번에 표준화할 수 있거든요. 이 글에서 그 설계 철학과 실제 노하우를 풀어보겠습니다.
멀티 클라우드 환경이 늘어나면 자연스럽게 코드도 세 벌이 생깁니다. AWS는 Terraform, Azure는 ARM Template, FortiGate는 API 스크립트로 나눠 관리하다 보면 어느 순간 동기화가 깨지고, 한쪽만 변경된 채 배포되는 사고가 나오더라고요. 표준화된 Module 구조 없이 시작하면 처음에는 빠르지만, 6개월쯤 지나면 누가 무엇을 어디에 배포했는지조차 추적이 안 되는 상황까지 가게 됩니다.
Terraform을 멀티 클라우드 표준 도구로 선택하는 이유는 HCL이라는 단일 언어 위에서 AWS, Azure, FortiGate Provider가 모두 동작하기 때문이거든요. 핵심은 Module을 어떻게 쪼개고, 어떻게 변수를 노출하느냐에 따라 운영 효율이 완전히 달라진다는 점입니다.
아래 본문에서는 Module을 실제로 어떻게 설계해야 FortiGate, AWS, Azure 세 영역을 한꺼번에 표준화할 수 있는지 단계별로 정리해 보겠습니다. 단순히 코드 예제를 나열하는 수준이 아니라, 운영자가 반드시 짚고 가야 할 설계 결정 포인트까지 다루었습니다.
📌 이 글의 핵심 정리
- Terraform Module 설계는 멀티 클라우드 표준화의 출발점이며, 변수 인터페이스 통일 여부가 성패를 가릅니다.
- FortiGate Module은 보안 정책과 네트워크 토폴로지를 변수로 추상화해 Provider 종속성을 줄여야 합니다.
- AWS와 Azure Module은 공통 변수 스키마를 공유하되 Provider별 리소스 블록만 분리하는 하이브리드 구조가 효과적입니다.
- 하드코딩된 리전과 인스턴스 사양은 반드시 변수화해야 하며, locals 블록으로 기본값을 안전하게 관리합니다.
- Ansible, Pulumi, CloudFormation과 비교 시 멀티 클라우드 일관성 측면에서 Terraform이 우위를 보입니다.
- 실패 사례에서 배우듯 Provider 버전 고정과 의존성 분리가 Module 안정성의 핵심입니다.
Terraform Module, 왜 멀티 클라우드 표준화의 첫 단계인가
Module이 멀티 클라우드를 연결하는 이유
Terraform Module은 단순한 코드 묶음이 아니라 인프라 추상화 계층입니다. AWS, Azure, FortiGate라는 서로 다른 Provider를 별개의 코드로 다루는 것이 아니라, Module이라는 동일한 인터페이스로 감싸면 호출자는 Provider가 무엇인지 신경 쓰지 않고 동일한 변수만 넘길 수 있거든요. 이런 구조가 바로 멀티 클라우드 표준화의 본질입니다.
실무에서 자주 쓰는 Module 구조는 크게 세 가지로 나뉩니다. 루트 Module은 환경별 호출 지점이고, 공통 Module은 변수와 output 인터페이스를 정의한 표준 라이브러리이며, Provider별 Module은 AWS, Azure, FortiGate 전용 리소스를 담는 하위 디렉터리입니다. 이 세 계층을 명확히 분리해 두면, 신규 클라우드를 추가할 때도 기존 호출 코드를 거의 건드리지 않아도 됩니다.
표준 변수 스키마가 가져오는 일관성
변수 이름을 project_name, environment, region, vpc_cidr처럼 통일하면, 개발자가 환경마다 다른 변수명을 외울 필요가 없어집니다. 결국 표준 변수 스키마가 팀의 학습 비용을 줄이고 코드 리뷰 시간도 단축시켜 주더라고요.
특히 멀티 클라우드에서는 같은 의미의 변수를 AWS에서는 region, Azure에서는 location, FortiGate에서는 zone으로 부르는 함정이 있거든요. 이런 명칭 차이를 Module 입력 단계에서 정규화해 두면, 호출자는 일관된 변수만 다루면 됩니다.
⚠️ Terraform Module 설계 주의
- Module 입력 변수를 너무 많이 노출하면 호출자의 부담이 커집니다. 필수 변수와 옵션 변수를 명확히 분리하세요.
- 루트 Module에서 하드코딩된 값을 그대로 Module 안으로 넘기면 표준화 효과가 절반으로 줄어듭니다.
FortiGate Module 설계의 핵심 원칙
FortiOS API 특성을 고려한 Module 분할
FortiGate Module은 보통 fortios Provider를 사용합니다. 이 Provider는 firewall policy, address 객체, interface 같은 FortiOS 자원을 HCL로 선언할 수 있게 해주는데, 문제는 한 번의 terraform apply로 너무 많은 정책을 변경하면 장비 부하가 커진다는 점이거든요. 그래서 Module을 정책 단위로 잘게 쪼개는 것이 핵심입니다.
예를 들어 fortigate-firewall-policy, fortigate-address-object, fortigate-vip 같은 식으로 분리해 두면, 운영 중 정책만 수정할 때 해당 Module만 별도로 plan/apply가 가능합니다. 결과적으로 장애 확산을 막고 변경 영향도를 명확히 추적할 수 있더라고요.
변수 추상화 패턴
FortiGate Module은 아래 변수 체계를 기본으로 가져갑니다.
- hostname: FortiGate 장비 식별자, 멀티 디바이스 환경에서 충돌 방지
- mgmt_cidr: 관리 접근을 허용할 CIDR 블록
- policy_rules: 방화벽 정책을 맵 형태로 받는 리스트 변수
- license_token: FortiFlex 라이선스 토큰, 변수화 필수
이렇게 리스트 변수로 정책을 받으면, 호출자가 정책을 추가하거나 변경할 때 Module 내부 코드를 한 줄도 수정하지 않아도 됩니다. 데이터 주도 설계가 FortiGate 운영에서도 효과적인 이유입니다.
💡 FortiGate Module 꿀팁
- fortios Provider 버전은 Module 변수(required_providers)에서 명시적으로 고정해 두세요. 1.0.0 미만과 1.0.0 이상에서 리소스 스키마가 달라지는 경우가 있습니다.
- VIP와 정책 변경을 같은 Module에 묶으면 순서 의존성이 생기므로 VIP를 별도 Module로 분리하는 편이 안전합니다.
AWS Provider 표준 Module 패턴
네트워크·컴퓨트·보안 3계층 Module 구조
AWS Module을 설계할 때 가장 무난하게 통하는 구조는 네트워크, 컴퓨트, 보안 3계층 분리입니다. 네트워크 Module은 VPC, 서브넷, 라우팅 테이블을 다루고, 컴퓨트 Module은 EC2, Auto Scaling Group을, 보안 Module은 보안 그룹, IAM Role을 책임지거든요. 이렇게 쪼개두면 리소스 단위로 변경 영향도를 제한할 수 있습니다.
특히 vpc_module을 단독으로 분리해 두면, 신규 리전에 동일한 VPC 토폴로지를 복제하기가 쉬워집니다. 실제로 서울 리전 VPC를 만든 Module을 호출하면서 region 변수만 도쿄로 바꾸면, 거의 동일한 네트워크 구조가 자동으로 만들어지더라고요.
AWS Module 입력 변수 표준 표
아래 표는 멀티 클라우드 표준 변수 스키마를 AWS에 적용한 예시입니다. 다른 Provider Module도 이 형태를 그대로 따라가게 만들면, 호출자는 변수 세트 하나만 익히면 됩니다.
| 변수명 | 타입 | 설명 | 기본값 |
|---|---|---|---|
| project_name | string | 프로젝트 식별자, 태그 prefix로 사용 | 필수 |
| environment | string | dev / stg / prod 구분 | dev |
| region | string | AWS 리전 코드 | ap-northeast-2 |
| vpc_cidr | string | VPC 대역폭 | 10.0.0.0/16 |
| instance_type | string | EC2 인스턴스 타입 | t3.medium |
이 변수 체계를 그대로 Azure Module에도 복제하면, 호출자는 사실상 Provider 차이를 의식하지 않고 동일한 tfvars 파일을 재사용할 수 있습니다.
Azure Provider 표준 Module 패턴
azurerm Provider 특유의 명명 규칙 처리
Azure는 resource_group, location, resource_name 같은 명명 규칙이 AWS와 다릅니다. 그래서 Azure Module 내부에서 resource_group_name이라는 변수를 별도로 받되, 외부 입력은 표준 변수인 project_name + environment 조합으로 합성하는 식의 변수 변환 어댑터 패턴을 쓰면 효과적이거든요.
실제 Module 내부에서 local.rg_name = “${var.project_name}-${var.environment}-rg”처럼 locals 블록으로 표준 변수로부터 Azure 고유 명칭을 만들어 내면, 호출자는 한 번의 변수 선언만으로 AWS와 Azure 양쪽에 동일한 명명 규칙을 적용할 수 있습니다.
멀티 클라우드 리소스 매핑 표
| 기능 영역 | AWS | Azure | FortiGate |
|---|---|---|---|
| 네트워크 격리 | VPC | VNet | VDOM |
| 서브넷 단위 | Subnet | Subnet | Interface |
| 보안 정책 | Security Group | NSG | Firewall Policy |
| ID 관리 | IAM Role | Managed Identity | Admin Profile |
| 로드밸런서 | ALB/NLB | Load Balancer | SLB |
이 매핑 표를 토대로 Module 이름 짓기 규칙을 정하면, 팀 내 검색성과 재사용성이 모두 좋아집니다. 예를 들어 module.network-isolation이라는 추상 이름 아래에 Provider별 구현을 배치하는 식으로요.
실패 사례에서 배우는 Module 설계 노하우
실패 사례 — 하드코딩으로 무너진 멀티 리전 배포
한 프로젝트에서 처음 FortiGate Module을 만들 때, 리전을 ap-northeast-2로, AMI를 ami-0abc123…처럼 특정 값으로 직접 박아 넣었습니다. 서울에서는 잘 동작했는데, 같은 코드를 도쿄 리전에 그대로 복사해 쓰니 FortiGate 인스턴스가 아예 뜨지 않더라고요. 원인은 두 가지였습니다.
- AMI ID가 서울 리전 전용이었기 때문에 도쿄에서는 존재하지 않는 이미지라 배포가 실패
- CIDR 블록이 10.0.0.0/16으로 고정되어, 기존 VPC와 충돌하는 경우 plan 단계에서 멈춰버림
결국 모듈 내부 코드를 Provider별로 분기하던 단순한 구조로는 한계가 분명했고, 운영팀은 새벽에 급하게 코드를 패치해 다시 배포하는 삽질을 반복했었습니다. 이 경험 이후 region, ami_id, cidr, instance_type을 모두 Module 입력 변수로 빼고, locals 블록에서 안전한 기본값을 정의하는 방식으로 전면 리팩토링했습니다.
해결 노하우 — 변수·Provider·State 3축 분리
개선한 구조는 크게 세 축으로 정리됩니다. 첫째, 변수 표준화로 region과 ami_id를 외부에서 주입받게 했고, 둘째, Provider 버전 명시로 fortios 1.0.0과 aws 5.x를 required_providers에서 고정했습니다. 셋째, State 분리로 멀티 리전·멀티 계정을 위한 backend 블록을 환경별로 따로 두어, 한 리전의 plan 실패가 다른 리전에 영향을 주지 않게 격리했거든요.
⚠️ Module 장애 확산 주의
- 하나의 루트 Module에서 모든 리전을 동시에 apply하면, 한 리전의 실패가 전체 plan을 멈추게 합니다. State 파일을 리전별로 분리해 두세요.
- Module 안에 time_sleep, null_resource 같은 우회 리소스를 남발하면 의존성 그래프가 꼬여 plan이 불안정해집니다.
다른 IaC 도구와의 비교 분석
Terraform vs Ansible, Pulumi, CloudFormation
멀티 클라우드 IaC 도구를 선택할 때 자주 비교되는 후보들이 있거든요. Ansible은 구성 관리와 배포 자동화에 강점이 있지만 선언적 인프라 모델링은 약하고, Pulumi는 코드 친화적 언어(TypeScript, Go)를 제공하지만 FortiGate와 같은 보안 어플라이언스 Provider 생태계가 얇습니다. AWS 전용이라면 CloudFormation이 강력하지만, Azure와 FortiGate까지 다루기엔 한계가 뚜렷하죠.
| 도구 | 멀티 클라우드 일관성 | FortiGate 지원 | Module 재사용성 | 학습 비용 |
|---|---|---|---|---|
| Terraform | 매우 높음 | fortios Provider 제공 | 공식 Module Registry 풍부 | 중간 |
| Ansible | 중간 | Collection으로 가능 | Role 단위 재사용 | 낮음 |
| Pulumi | 높음 | Provider 부족 | 언어별 패키지 | 중간~높음 |
| CloudFormation | AWS 전용 | 불가 | Nested Stack | 중간 |
| ARM Templates | Azure 전용 | 불가 | Linked Template | 중간 |
표에서 보듯 FortiGate와 멀티 클라우드를 동시에 다루는 시나리오에서는 Terraform이 가장 균형 잡힌 선택지입니다.
Terraform만의 차별화된 통찰
다른 도구와 비교했을 때 Terraform만이 가진 강점은 선언적 상태 모델입니다. plan 단계에서 실제 변경 사항을 미리 보여주기 때문에, 멀티 클라우드에서 특히 무서운 드ift를 사전에 발견할 수 있거든요. 또한 State Lock과 Remote Backend 조합은 멀티 사용자 환경에서 동시성 문제를 꽤 우아하게 해결해 줍니다.
💡 멀티 클라우드 표준화 꿀팁
- Module Registry에 사내 Module을 게시하고, semantic versioning 규칙을 적용하면 Provider와 독립적인 버전 관리가 가능합니다.
- terraform-docs로 Module README를 자동 생성하면, 신규 합류자도 변수 스키마를 빠르게 파악할 수 있습니다.
자주 묻는 질문
Q. FortiGate Module을 만들 때 가장 먼저 변수화해야 할 항목은 무엇인가요?
A. 리전과 라이선스 토큰부터 변수화하는 편이 안전합니다. 이 두 값이 하드코딩되면 멀티 리전과 멀티 디바이스 확장이 즉시 막히거든요. 그 다음으로 방화벽 정책과 address 객체를 리스트 변수로 받아 데이터 주도 구조로 전환하면 운영이 한결 수월해집니다.
Q. AWS와 Azure Module을 같은 변수 스키마로 묶을 수 있나요?
A. 가능합니다. 외부 입력은 project_name, environment, region, vpc_cidr 같은 표준 변수로 통일하고, Module 내부에서 Provider별 명칭(예: location, resource_group_name)을 locals 블록으로 합성하는 어댑터 패턴을 쓰면 호출자는 사실상 Provider를 의식하지 않아도 됩니다.
Q. Module 버전 충돌이 자주 발생하는데 어떻게 관리하나요?
A. required_providers 블록에서 fortios, aws, azurerm Provider 버전을 명시적으로 고정하고, Module 자체에도 semantic versioning을 적용해 변경 영향도를 통제하는 편이 좋습니다. State 파일을 리전·계정별로 분리해 두면 한 곳의 충돌이 다른 환경으로 번지지 않습니다.
Q. Terraform과 Ansible을 같이 써야 하는 상황도 있나요?
A. 있습니다. Terraform으로 인프라 토폴로지를 선언하고, Ansible로 VM 내부 구성(패키지 설치, 설정 파일 적용)을 담당하는 역할 분담이 실무에서 자주 쓰이거든요. 다만 IaC 일관성이 깨질 수 있으니, 호출 지점을 명확히 분리하고 어떤 단계에서 어떤 도구를 쓰는지 문서화해 두는 편이 안전합니다.
멀티 클라우드 표준화는 한 번에 완성되는 것이 아니라, Module을 작게 쪼개고 변수 인터페이스를 점진적으로 통일해 가며 다듬어 가는 과정입니다. 오늘 정리한 변수 표준화, Provider 분리, 실패 사례 노하우, 그리고 IaC 도구 비교가 그 과정에서 길잡이 역할을 했으면 합니다. 처음부터 완벽한 구조를 만들려기보다, 작은 Module 하나라도 표준 변수 스키마로 출시해 보는 것이 멀티 클라우드 표준화의 실질적인 첫걸음입니다.
본 글에서 언급된 FortiGate, AWS, Azure 서비스와 Terraform Module 설계 방식은 참고용 정보로 제공되며, 실제 적용 시에는 각 클라우드 제공자의 최신 공식 가이드와 FortiOS 릴리즈 노트를 반드시 확인하시기 바랍니다. 본 콘텐츠는 특정 환경에서의 보장을 약속하지 않으며, 도입 판단은 사용자 환경에 따라 신중히 진행해 주세요.