Stack 인증하기

Stack 인증하기 (Authenticate a Stack)

Stack을 인증하는 방법은 두 가지예요.

출처: 문서

본문

  • store 블록 — HCP Terraform 변수 집합(variable set)의 값을 참조할 수 있게 해줘요.
  • identity_token 블록 — OIDC 인증용 JSON Web Token(JWT)을 생성해요.

OIDC로 Stack을 인증하는 것을 권장해요. 정적 자격증명(static credentials)으로 프로바이더를 인증하는 것은 자격증명을 정기적으로 교체하더라도 보안 위험을 제기하기 때문이에요. OIDC로 인증을 정의하는 것은 인프라에 관한 모든 것을 코드로 정의하는 Stack 원칙과도 부합해요.

OIDC로 인증하기 (Authenticate with OIDC)

OpenID Connect(OIDC)는 OAuth 2.0 프로토콜 위의 ID 계층이에요. OpenID Connect 프로토콜을 기반으로 구축된 HCP Terraform의 워크로드 ID 토큰을 사용해서 Stacks를 클라우드 프로바이더에 안전하게 연결·인증할 수 있어요.

직접 해보기: HCP Terraform으로 Stack 배포 튜토리얼에서 Stack용 OIDC 설정을 단계별로 해보세요.

Stacks에는 워크로드 ID 토큰(JWT 토큰)을 만드는 내장 identity_token 블록이 있어요. 이 토큰들을 사용해 Stacks를 테라폼 프로바이더에 안전하게 인증할 수 있어요.

개요 (Overview)

Stack 인증의 세부 사항은 설정하는 클라우드 프로바이더에 따라 다르지만, 기본 단계는 동일해요.

  1. 클라우드 프로바이더와 HCP Terraform 간의 트러스트 구성을 설정해요. 이는 보통 클라우드 프로바이더를 위한 역할(roles)과 정책(policies)을 만드는 것을 포함해요.
  2. 이전 단계에서 만든 audience와 역할을 사용해 Stack의 배포 파일에 identity_token 블록을 추가해요.

배포는 identity_token 블록의 값을 참조해서 트러스트 관계 역할을 Stack의 작업에 전달할 수 있어요.

트러스트 구성 설정 (Configure trust configuration)

이 예제에서 AWS로 예시 트러스트 정책을 설정해 볼게요. 다른 프로바이더로 트러스트 정책을 설정하는 예시는 예제 구성 저장소를 참고하세요.

인증하려는 클라우드 프로바이더에 대한 트러스트 관계와 권한을 만들고 구성하는 데 테라폼을 사용하는 것을 권장해요. 다음 테라폼 구성으로 새 워크스페이스를 만들고, 특정 설정에 맞게 aws_region, tf_organization, tf_project, tf_stack 변수를 구성하세요.

# main.tf
variable "aws_region" {
  type        = string
  description = "The AWS region to create the role in."
}

variable "tf_organization" {
  type        = string
  description = "The name of the organization that this workspace and Stack live in."
}

variable "tf_project" {
  type        = string
  description = "The name of the project that this workspace and Stack live in."
}

variable "tf_stack" {
  type        = string
  description = "The name of the Stack you will you use this token in."
}

provider "aws" {
  region = var.aws_region
}

resource "aws_iam_openid_connect_provider" "stacks_openid_provider" {
  url            = "https://app.terraform.io"
  client_id_list = ["aws.workload.identity"]

  # This is the thumbprint of https://app.terraform.io as of 2024/08/07
  # Refer to "Adjust access of trust" to learn how to update this thumbprint
  thumbprint_list = ["9e99a48a9960b14926bb7f3b02e22da2b0ab7280"]
}

resource "aws_iam_role" "stacks_role" {
  name               = "stacks-${var.tf_organization}-${var.tf_project}-${var.tf_stack}"
  assume_role_policy = data.aws_iam_policy_document.stacks_role_policy.json
}

data "aws_iam_policy_document" "stacks_role_policy" {
  statement {
    effect = "Allow"
    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.stacks_openid_provider.arn]
    }
    actions = ["sts:AssumeRoleWithWebIdentity"]
    condition {
      test     = "StringEquals"
      variable = "app.terraform.io:aud"
      values   = ["aws.workload.identity"]
    }
    condition {
      test     = "StringLike"
      variable = "app.terraform.io:sub"
      # This value dictates which HCP Terraform organizations, projects,
      # and stacks can assume the new role you are creating.
      #
      # You can widen access to an entire organization or project by
      # tweaking the value below. You can also restrict access to specific
      # deployments or operations. Refer to Configure trust for more information.
      values = ["organization:${var.tf_organization}:project:${var.tf_project}:stack:${var.tf_stack}:*"]
    }
  }
}

# Now, you give the new role access to things you want to manage in your Stack.
#
# The policies below are too broad for a production use case, but you set them
# broadly for now to ensure this Stacks can do anything during development and
# testing. In practice, only give your Stack access to what it needs to manage.

resource "aws_iam_role_policy_attachment" "iam" {
  role       = aws_iam_role.stacks_role.name
  policy_arn = "arn:aws:iam::aws:policy/IAMFullAccess"
}

resource "aws_iam_role_policy_attachment" "sudo" {
  role       = aws_iam_role.stacks_role.name
  policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess"
}

# Your workspace returns this output role, which you use to configure your
# deployments.
output "role_arn" {
  value = aws_iam_role.stacks_role.arn
}

HCP Terraform에서 워크스페이스를 설정한 뒤 plan과 apply 작업을 수행해요. HCP Terraform은 OpenID 프로바이더, 정책, 역할을 만든 다음 role_arn 출력으로 새 역할의 ARN을 출력할 거예요. 새 AWS ARN 역할을 복사하세요. 이것이 Stack과 HCP Terraform으로 클라우드 프로바이더를 구성할 때 사용하는 값이에요.

워크로드 ID 트러스트 클레임과 메타데이터에 대해 더 알아보려면 identity_token 블록 레퍼런스를 참고하세요.

HCP Terraform 구성 (Configure HCP Terraform)

Stacks는 identity_token 블록으로 특정 배포의 JSON Web Token(JWT)을 정의해요. 이 토큰은 OIDC 기반 인증을 가능하게 해서, Stack 배포가 AWS, Azure, GCP 같은 클라우드 프로바이더에 안전하게 연결되게 해줘요.

identity_token 블록을 정의할 때는 그 audience를 지정해요. 예를 들어 다음 Stack 배포 구성은 AWS audience를 지정하는 identity_token 블록을 정의해요.

identity_token "aws" {
  audience = ["aws.workload.identity"]
}

정의한 뒤에는 배포의 입력 변수에서 ID 토큰을 참조하고, 프로바이더 구성에서 그 토큰을 참조할 수 있어요.

AWS 리소스를 인증하기 위해 트러스트 관계로 토큰을 구성하려면 트러스트 관계(role ARN)도 추가해야 해요.

# deployments.tfdeploy.hcl
identity_token "aws" {
  audience = ["aws.workload.identity"]
}

deployment "development" {
  inputs = {
    role_arn       = "<YOUR_ROLE_ARN>"
    identity_token = identity_token.aws.jwt
  }
}

이제 배포는 AWS로 인증되며, 인증을 위해 트러스트 구성을 Stack의 프로바이더에 전달할 수 있어요.

# variables.tfcomponent.hcl

variable "role_arn" {
  type = string
}

variable "identity_token" {
  type      = string
  ephemeral = true
}

# providers.tfcomponent.hcl

required_providers {
  aws = {
    source  = "hashicorp/aws"
    version = "~> 5.7.0"
  }
}

provider "aws" "this" {
  config {
    region = var.region
    assume_role_with_web_identity {
      role_arn           = var.role_arn
      web_identity_token = var.identity_token
    }
  }
}

이 설정에서 각 배포는 Stack을 plan하거나 apply할 때마다 트러스트 관계 역할의 ARN과 AWS가 생성한 JWT 토큰을 전달해요. 각 배포는 필요한 특정 권한으로 구성된 자신만의 역할을 사용해요.

다른 프로바이더로 OIDC를 설정하는 더 많은 예시는 예제 구성 저장소를 참고하세요.

변수 집합으로 인증하기 (Authenticate with a variable set)

HCP Terraform 변수 집합에 저장된 자격증명에 접근하려면 store 블록을 사용할 수 있어요. 어떤 구성을 작성하기 전에, 프로젝트가 변수 집합에 접근하도록 허용하거나 그 집합을 전역적으로 사용 가능하게 만들어, Stack이 대상 변수 집합에 접근할 수 있는지 확인하세요.

다음으로 배포 구성 파일에 store 블록을 추가해서 변수 집합의 값에 접근해요.

# deployments.tfdeploy.hcl
store "varset" "tokens" {
  name     = "Example_Varset_Name"
  category = "env"
}

정의한 뒤에는 배포가 변수 집합의 값에 접근할 수 있어요. 다음 예제에서 test 배포는 tokens store를 사용해 Example_Varset_Name이라는 변수 집합에 접근해요.

# deployments.tfdeploy.hcl
store "varset" "tokens" {
  name     = "Example_Varset_Name"
  category = "env"
}

deployment "test" {
  inputs = {
    access_key    = store.varset.tokens.AWS_ACCESS_KEY_ID
    secret_key    = store.varset.tokens.AWS_SECRET_ACCESS_KEY
    session_token = store.varset.tokens.AWS_SESSION_TOKEN
  }
}

store 블록을 정의한 뒤 배포는 store.varset.<STORE_NAME>.<VARIABLE_NAME> 문법으로 그 변수 집합의 특정 값을 참조할 수 있어요. test 배포는 변수 값을 입력으로 전달해서 프로바이더와 컴포넌트가 그 값들을 사용하게 해요.

# providers.tfcomponent.hcl
variable "access_key" {
  description = "AWS access key"
  type        = string
  ephemeral   = true
}

variable "secret_key" {
  description = "AWS sensitive secret key."
  type        = string
  sensitive   = true
  ephemeral   = true
}

variable "session_token" {
  description = "AWS session token."
  type        = string
  sensitive   = true
  ephemeral   = true
}

required_providers {
  aws = {
    source  = "hashicorp/aws"
    version = "~> 5.7.0"
  }
}

provider "aws" "this" {
  config {
    access_key = var.access_key
    secret_key = var.secret_key
    token      = var.session_token
  }
}

기본적으로 Stacks 배포는 변수 집합의 값이 비밀번호나 API 키 같은 민감한 데이터를 포함하는 경우가 많기 때문에 변수 집합의 값을 state에 저장하지 않아요. 라이선스 키처럼 배포 state에 유지해야 하는 변수의 경우 stable 키워드를 사용할 수 있어요. 자세한 내용은 배포를 위한 store 값 유지(Persist store values for deployments)를 참고하세요.

store 블록에 대한 더 많은 정보와 예시는 store 블록 레퍼런스를 참고하세요.

더 알아보기 (Learn more)