본문 바로가기

DevOps

[Terraform] AWS 인증 1. Authentication 우선 순위

Terraform 공식 문서에 따르면, Terraform에서 AWS의 인증은 아래의 순서로 적용된다고 설명되어 있습니다. 
그리고 그 아래에 assuming an IAM role을 지원한다고 추가로 언급하고 있습니다.

  1. Parameters in the provider configuration : Provider 설정할 때 파라미터 값으로 Access key, Secret Key 값 전달
  2. Environment variable: 환경 변수에 key값 지정
  3. Shared credentials files
  4. Shared configuration files : 3, 4번은 하나의 항목으로 보는 것이 더 좋을 것 같습니다. .aws폴더에 credential 파일과 config 파일 관리하기.
  5. Container credentials
  6. Instance profile credentials and region

기본적으로 AWS CLI와 SDK의 우선순위와 일치한다고 적혀있기도 하고, 실제로 비슷한 것 같습니다. 

  • 1번은 Terraform provider 파라미터를 이용하는 방법이고,
  • 2~4번은 CLI에서 쓰던 방법입니다. 1~4번까지 간단히 정리해 보겠습니다. 
  • 5, 6번은 컨테이너 등 특수한 경우에 사용이 되는 것이라 생략하고, 
  • 추가로 설명이 되어 있는 Assuming a role 방법이 있는데, CDH에 적용되어 있는 OpenID Connect를 이용하는 방법에 대해서는 다음 Post에서 간단히 설명하도록 하겠습니다. 

 

1. Provider configuration parameter 방법

 

Terraform에서 Provider란?

Terraform document에 아래와 같이 정의되어 있습니다.

Providers are a logical abstraction of an upstream API. They are responsible for understanding API interactions and exposing resources.

" 논리적 추상화.. 당췌 무슨 말인지.. "

Terraform은 IaC, 즉 Infrastructure as Code 도구 입니다. Code로 인프라를 관리하기 위해서는 Code로 관리할 수 있는 대상이 있어야 하겠지요.. 즉, 그 대상에서 API 또는 SDK를 제공해야 가능한 얘기일 것 같습니다.

Terraform에서 Provider라고 하는 이유도 그런 API, SDK를 제공(Provide)하기 때문일 것 같습니다. 현재 수백개의 Provider가 존재한다고 합니다. AWS, GPC와 같이 API를 제공하는 Public Cloud Provider가 대표적인 Provider라고 할 수 있습니다. 

AWS Provider를 사용하여 AWS 계정의 리소스를 관리하는 경우를 살펴보겠습니다. 

테라폼으로 AWS과의 상호 작용 즉 EC2, S3와 같은 리소스를 만들거나 수정하기 위해서 따라야 할 규칙이 정해져 있습니다. 그 규칙을 확인하기 위해서는 테라폼 공식 문서를 확인해야 합니다. 

AWS Provider: https://registry.terraform.io/providers/hashicorp/aws/latest/docs

 

Terraform Registry

 

registry.terraform.io

AWS Provider를 설정하고, AWS Resource를 관리하기 위해서는 대상 계정의 AWS 환경에 인증을 받아야 합니다. 

 

 

다시 처음으로 돌아가서, Provider configuration parameter로 인증을 한다는 것은, Provider 설정할 때 인증과 관련된 변수, Parameter로 전달한다는 의미 입니다.

AWS의 리소스를 Terraform으로 관리하기 위해 가장 먼저 Provider 블럭에 Provider를 지정해야 합니다. 보통은 main.tf 또는 providers.tf 파일에 지정합니다.

provider "aws" {  
  region = "ap-northeast-2"  
  access_key = "ASFESDFSDTW$ER"                       # AWS Access Key  
  secret_key = "dlfksjdflksjdflksjdfs/@#$sdf2#$"      # AWS Secret Access Key
}

access_key, securet_access_key 파라미터에는 AWS IAM에서 user별 Access key 설정에서 생성할 수 있는 Aceess key, Secret  Access Key를 지정할 수 있습니다. 이 두 Key는 시스템적으로 Program 방식으로 인증 정보를 전달 할 때 필요한 비밀번호와 같은 역할을 하는 것 입니다. 

이 두개의 Key 쌍이 있으면, AWS CLI로 AWS 환경에 접속해서 그 사용자가 가지고 있는 권한으로 작업이 가능합니다.

특히 Terraform 사용자는 일반적으로 Admin 권한은 가지고 있기 때문에 이 key들이 유출되지 않도록 관리하는 것이 무엇보다 중요합니다.

Admin 권한의 사용자의 Key가 내어 주는 것은 회사의 데이터 센터의 열쇠를 내어 주는 것과 같다고 할 수 있습니다. 

 

위의 예에서 access_key와 secret_key에 Key 값을 그대로 입력해 놓는 것은 원리를 이해하기 위해 개인적으로 테스트 할 때 정도만 사용하는 것을 권장합니다. 

위와 같이 파라미터로 key를 전달할 때 코드를 변수로 전달하고 숨기는 방법도 있습니다. 

 

Terraform을 이용해서 AWS EC2 Instance를 하나 만들어 보겠습니다. 숨기지 않는 방법입니다. 

# instance.tf

provider "aws" {  
  access_key = "[YOUR-ACCESS-KEY]"  
  secret_key = "[YOUR-SECRET-ACCESS-KEY]"  
  region     = "ap-northeast-2"
} 

resource "aws_instance" "example" {
  ami           = "ami-0ea4d4b8dc1e46212"  
  instance_type = "t2.micro"  
  subnet_id     = "subnet-05f368829fba4ae2z"
}

위 instance.tf 파일에서 Provider 설정을 하였고, parameter key 값을 그대로 파일에 적어 놓았습니다. 그리고 같은 파일에서 Instance 리소스를 생성하고 있습니다. 

 

다음은 코드를 숨기는 방법입니다. 

provider.tf 파일을 만들어 provider block을 분리하고,  var.AWS_ACCESS_KEY와 같이 변수를 key의 값으로 부여했습니다.

# provider.tf

provider "aws" {
  access_key = var.AWS_ACCESS_KEY
  secret_key = var.AWS_SECRET_KEY
  region     = var.AWS_REGION
}

변수를 관리하기 위햇 vars.tf  파일에 variable block으로 변수들을 선언합니다.

순서는 상관 없습니다. 변수를 사용하기 위해서는 어딘가에는 변수를 정의해 놓아야 합니다. 

variable “변수이름” {} 구문은 변수를 정의를 담당합니다.

값을 지정하는 방법으로 default = “을 지정하면 기본 값 지정이 가능합니다.

# vars.tf

variable "AWS_ACCESS_KEY" {
}
variable "AWS_SECRET_KEY" {
}
variable "AWS_REGION" {
  default = "ap-northeast-2"
}

실제 Key의 값은 terraform.tfvars 파일에 적어 놓을 수 있습니다. 

# terraform.tfvars

AWS_ACCESS_KEY     	= "[YOUR-ACCESS-KEY]"
AWS_SECRET_KEY 		= "[YOUR-SECRET-ACCESS-KEY]"
AWS_REGION     		= "ap-northeast-2"

리소스를 설정하는 instance.tf 과 같은 파일은 리소스 별로 별도로 관리하면 좋습니다. 

# instance.tf

resource "aws_instance" "example" {
  ami           = "ami-0ea4d4b8dc1e46212"
  instance_type = "t2.micro"
  subnet_id     = "subnet-05f368829fba4ae2z"
}

aws_instance 리소스  "example"로 인스턴스를 만들 때, image와 instance_type과 subnet을 지정해 주고 있습니다. 
|instance.tf에서 ami id, subnet ID 등도 아주 민감한 정보는 아니지만 변수로 처리하는 것이 좋습니다. 

 

terraform.tfvars 파일에 key의 실제 값을 적어 놓는 것은 괜찮을까요?


보통 .gitignore 파일에 *.tfvars을 등록하면, tfvars 파일은 git으로 소스 반영시 Repository에 저장하지 않고 관리자 PC에서만 관리할 수 있습니다. 이 방법으로 민감한 정보는 .tfvars파일에 관리하기도 합니다. 

 

아래 링크는 구글에서 terraform gitignore로 검색하면 찾을 수 있는 terraform 관련 .gitignore 설정이니 참고하세요.
https://github.com/github/gitignore/blob/main/Terraform.gitignore

 

 

2. 환경 변수(Environment variables) 지정하는 방법

 

Provider를 설정할 때 Parameter를 지정하는 것은 강제로 주입하는 것이기 때문에 가장 우선합니다. 

 

Parameter가 없으면, 그 다음으로 환경 변수가 지정되어 있는지 확인합니다. 
인증을 위해서는 아래와 같은 환경 변수가 필요합니다.  

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_REGION 또는 AWS_DEFAULT_REGION
  • AWS_SESSION_TOKEN (필요시)

Parameter가 넘어 오지 않았는데, 환경 변수 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 값을 읽었더니 값이 있었다고 하면 이 값으로 로그인 할 수 있습니다.


이 환경 변수는 AWS CLI를 사용할 때도 동일한 방법으로 사용되는 방법입니다. 다시 말해 환경 변수가 지정되어 있다면, "원래 쓰던 AWS 계정이 있군.." 하면서 terraform이 provider에 필요한 access_key, secret_key값을 환경 변수로 알아서 채워 준다고 보면 될 것 같습니다. 

 

환경변수를 .bash_profile 같은 파일이나, 윈도우의 시스템 환경 변수에 등록해서 사용하는 경우도 있겠지만, 개인이 단일 계정을 관리하는 경우라면 가능한 얘기이지만, 여러 계정을 관리하는 경우는 매번 변수를 변경해 주어야 합니다. 

오히려 Github Workflow같은 Script 또는 다른 방법으로 동적으로 환경변수를 지정하고 인증을 받는 방법이 많이 사용됩니다. 

 

 

3. Shared Credential, Config 파일을 사용하는 방법

 

처음 AWS CLI를 설치하고 "aws configure" 명령어를 실행하면,  아래와 같이 access_key, secret key, region, 출력 방법을 입력하라고 합니다. 

aws configure

aws configure에서 입력한 값들은 <사용자 홈 디랙토리>\.aws 폴더에 credentials 파일과 config 파일에 저장되며, 아래와 같이 여러개의 계정을 관리하기 위해 profile을 추가로 등록하는 것이 가능합니다. 

(윈도우) <사용자 HOME>\.aws 폴더
config file
credentials file

위와 같이 credentials, config파일을 관리하고 있다면, 아래와 같이 Provider를 설정할 수 있습니다. 

provider "aws" {
  shared_config_files      = ["/Users/tf_user/.aws/conf"]
  shared_credentials_files = ["/Users/tf_user/.aws/creds"]
  profile                  = "allsol-dev"
}

 

지금까지 세가지 인증 방법을 간략히 살펴 보았습니다.

 

prod, dev 두 환경을 각각 다른 Account로 관리한다면, 어떻게 해야 할까요?

1번 Parameter를 전달하는 방법에서 prod.tfvars, dev.tfvars로 환경별 profile을 별도로 관리한 다음,  
terraform plan 또는 terraform apply를 실행할 때 --var-file 옵션에 tfvars 파일을 지정하면 됩니다. 

 

2번 환경변수를 사용하는 방법은 다음 포스트에서 설명드릴 assuming role에서 각 계정별 다른 assuming role을 부여 받을 때 환경변수가 자동 지정되므로 각 계정으로 인증 받을 때 사용될 수 있습니다. 

그 외에도 github action의 security 변수에 각각 다른 변수 명으로 저장해 놓은 다음 각 환경에 맞는 환경 변수를 인증하기 전 변경하는 방법으로 사용할 수 있습니다. 

 

3번 credentials, config 공유 파일을 이용하는 방법은 profile을 변수로 지정한 다음, plan, apply 실행할 때 var-file 또는 var 옵션을 써서 지정할 수 있습니다. 

 

assuming role 방법은 다음 Post에서 정리해 보겠습니다.  

감사합니다.