연재 시리즈

테라폼 시리즈 34편. 민감정보 보호

악분 2022. 11. 24. 20:59
반응형

영상: https://youtu.be/-ysCr2BsC1I

민감정보 노출되는 부분

테라폼의 민감정보(비밀번호 등)는 외부에 공개되거나 보안사고를 당했을 때 노출이 되는 문제가 있습니다. 민감정보가 노출될 수 있는 위치는 테라폼 코드와 상태파일 2종류입니다. 

 

provider block 민감정보

provider block에서 인증정보 설정가 민감정보에 해당합니다. 예로 aws provider에는 access_key와 secret_key가 민감정보입니다. 외부에 공개될 경우 인증정보가 그대로 노출되므로 절대 인증정보를 provider block에 설정하면 안됩니다.

provider "aws" {
  region     = "us-west-2"
  access_key = "my-access-key"
  secret_key = "my-secret-key"
}

 

첫 번째 보완 - 환경변수

첫 번째 보완방법은 환경변수로 인증정보를 설정합니다. provider마다 설정하는 환경변수가 다르므로 각 provider 공식문서를 참고해야 합니다. aws provider예제는 아래와 같습니다.

$ export AWS_ACCESS_KEY_ID="my-access-key"
$ export AWS_SECRET_ACCESS_KEY="my-secret-key"

 

두 번째 보완 - 설정파일

두 번째 보완 방법은 provider 설정파일에 직접 인증정보를 설정하는 방법입니다. 테라폼은 provider에 인증정보가 없고 환경변수도 설정이 안되어 있으면 provider 설정파일을 바라봅니다. aws에서는 aws configure명령어로 인증정보를 파일에 저장할 수 있습니다. 

aws configure

 

세 번째 보완 - 임시 보안자격증명

두 번째 보완 방법인 설정파일은 보안사고 등으로 인증정보가 노출되면 시스템이 위험해질 수 있습니다. 특히 강력한 권한을 가지고 있으면 위험도가 증가합니다.

 

그래서 aws 모범사례에서는 설정파일에 IAM user 인증정보(장기 보안자격증명)를 직접 사용하는 것보다 임시 보안자격증명을 사용하는 것을 권장합니다.

 

첫 번째 예제 - EC2인턴스에서 임시 보안자격증명 발급

첫 번째 예제는 aws가 주체가되어 사용자 요청을 검증하고 임시 보안자격증명을 발급받습니다. 예제에서는 EC2 Instance에 IAM Role을 설정하여 AWS에게 인증을 받고 임시 보안자격증명을 발급은 후, s3에 접근합니다.

 

실습을 위해 aws인프라를 구축할건데요. aws인프라는 테라폼 코드로 작성했습니다. 테라폼 코드는 너무 길어 github링크로 생략합니다.

테라폼 코드 링크: https://github.com/sungwook-practice/terraform-study/tree/main/week6/ec2_instance_with_ssh

 

테라폼을 실행하기 전에 ssh키쌍을 생성해야 합니다. ssh키쌍은 EC2 Instance에 원격접속할 때 사용합니다.

ssh-keygen -t rsa -b 4096 -f demo

 

그리고 s3 bucket 이름을 variable.tf에서 수정(또는 환경변수 오버라이딩)해야 합니다.

variable "bucket_name" {
  type        = string
  default     = "akbun-t101study-credexample"
  description = "bucket name"
}

 

terraform apply명령어를 실행하여 테라폼 코드를 aws에 반영합니다.

terraform apply

 

EC2 Instance가 잘 생성되었는지 확인하고 EC2 IAM Role이 잘 설정되었는지 확인합니다. 그리고 s3 bucket도 잘 생성되었는지 확인합니다.

 

EC2 Instance에 원격접속 후, aws s3 ls명령어를 사용해보세요. 놀랍게도 s3목록이 조회됩니다. aws 인증정보가 있는 설정파일이 없지만, aws 명령어를 사용할 때 임시 자격증명을 발급받았습니다. 그래서 aws 명령어가 잘 실행 된겁니다.

ssh -i demo ec2-user@<public ip>

 

임시 자격증명은 EC2 Instance metadata에서 확인할 수 있습니다. 임시 자격증명은 말 그대로 짧은 만료시간을 가지고 있습니다.

IAMROLE=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials)
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAMROLE

 

두 번째 예제 - github action에서 임시 보안자격증명 발급

두 번째 예제는 사용자가 AWS에게 임시 보안자격증명을 요청하지 않고 aws가 아닌 서비스에게 요청하는 방법입니다. aws가 아닌 서비스는 OIDC프로토콜을 이용하여 사용자게에 임시 보안자격증명을 발급합니다.

 

aws가 아닌 서비스를 외부자격증명 공급자(external Identity Provider)라고 부릅니다. 외부자격증명 공급자는 사용자가 임시 보안자격증명을 요청하면 aws Identity Provider에게 요청을 넘깁니다. aws Identity Provider는 검사가 성공적으로 수행되면 임시 보안자격증명을 발급하고 외부자격증명 공급자에게 전달합니다. 
결국은 aws Identity Provider가 검사와 임시 보안자격증명을 발급하지만 사용자 입장에서는 마치 aws아닌 서비스가 발급해주는 것처럼 느낍니다.

 

aws Identity Provider는 aws iam메뉴에서 생성할 수 있습니다. 아래 그림은 github OIDC를 추가한 예제입니다.

 

aws에서 provider추가와 함께 Role을 생성해야 합니다. Role은 OIDC Provider에서는 임시 보안자격증명 발급을 요청할 때 사용합니다. Role 신뢴관계의 Action은 AssumeRoleWithWebIdentity로 설정합니다.

 

github action에서 github OIDC를 이용하여 aws s3에 접근하는 예제를 실습해보겠습니다. aws Identity Provider와 Role은 테라폼 코드로 생성했습니다.

코드링크: https://github.com/sungwook-practice/terraform-study/tree/main/week6/github_action_aws-oidc
# aws Identity Provider
resource "aws_iam_openid_connect_provider" "github_oidc" {
  url = "https://token.actions.githubusercontent.com"

  client_id_list = [
    "sts.amazonaws.com"
  ]

  thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"]
}

# Role
data "aws_iam_policy_document" "github_allow" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRoleWithWebIdentity"]
    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.github_oidc.arn]
    }
    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values   = ["repo:sungwook-practice/aws-oidc:*"]

    }
  }
}

# Policy
data "aws_iam_policy_document" "policy_bucket_list" {
  statement {
    sid = "1"

    actions = [
      "s3:ListAllMyBuckets",
      "s3:GetBucketLocation",
    ]

    resources = [
      "arn:aws:s3:::*",
    ]
  }
}

.. 이하 생략

 

terraform apply명령어로 테라폼 코드를 인프라에 반영합니다.

terraform apply

 

IAM메뉴에서 aws Identity Provider에 github Provider가 추가되었는지 확인합니다.

 

IAM Role이 생성되었는지 확인합니다. Role의 Policy는 s3를 조회하는 권한이 추가되어 있습니다. github action이 있는 repo만 role을 사용할 수 있도록 조건문을 추가했습니다.

 

이제 github actino workflow를 생성합니다. workflow는 “aws-actions/configure-aws-credentials@master”템플릿을 사용하여 임시 보안자격증명을 발급받습니다. 내부적으로 github OIDC를 사용합니다. 임시 보안자격증명 발급 이후에 s3 bucket목록을 조회합니다.

name: aws-s3-test

on:
  push:
    branches: [ "main" ]

jobs:
 build:
   name: build
   permissions:
     id-token: write
     contents: write
     
   runs-on: ubuntu-18.04
   
   steps:
     - name: Checkout
       uses: actions/checkout@v2
      
     - name: Configure AWS Credentials
       uses: aws-actions/configure-aws-credentials@master
       with:
         aws-region: ap-northeast-2
         role-to-assume: arn:aws:iam::467606240901:role/GithubActionsRole
         role-session-name: GithubActionsSession
    
     - name: list bucket
       run: |
         aws s3 ls

 

workflow를 생성하면 main branch에 workflow파일이 생성되어 자동으로 github action이 실행됩니다. 실행 결과를 확인하면 s3 bucket목록을 잘 출력했습니다. 다시 말해, github action이 임시 보안자격증명을 잘 발급받고 aws API를 실행했습니다.

 

세 번째 보완 - 인증정보 관리 도구

세 번째 보완방법은 클라우드 인증정보를 관리하는 도구를 사용하는 방법입니다. 예제로 aws 인증정보를 관리하는 aws-valut를 살펴보겠습니다. 

aws-valut는 운영체제 비밀번호 관리 방법을 연동 안전하게 aws 인증정보를 저장합니다. 그리고 aws api를 사용할 때마다 임시 자격증명을 발급받아 인증정보 노출을 최소화 합니다.

 

aws-valut는 brew, choco 등 운영체제 소프트웨어 관리도구로 쉽게 설치할 수 있습니다.

# mac
brew install aws-vault

# window
choco install aws-vault

 

aws profile처럼 aws-valut도 profile단위로 관리됩니다. add명령어로 profile을 추가합니다.

aws-valut.exe add testuser

 

list명령어로 profile목록을 조회할 수 있습니다.

aws-valut.exe list

 

인증정보는 운영체제 비밀번호 관리 시스템에 저장됩니다. 윈도우 운영체제는 자격증명관리에 저장됩니다.

 

exec명령어로 profile을 선택하고 aws api를 실행할 수 있습니다.

aws-vault.exe exec testuser -- aws s3 ls

 

debug모드로 exec명령어를 실행하면 임시토큰을 발급받고 aws api를 실행하는 것을 알 수 있습니다.

 

terraform명령어도 exec명령어와 함께 실행할 수 있습니다.

aws-vault.exe exec testuser -- terraform init
반응형