Terraform을 이용해서 Amazon IVS Live Streams 및 Chat 배포하기 (Deploy Amazon IVS Live Streams and Chat with Terraform)
Tags: aws, terraform, devops, cloud
Published: 2023-01-31 02:12:30

> _Disclaimer
> 이 블로그 포스트는 Amazon IVS Engineer인 [Kevin Eady](https://dev.to/kevineady)가 포스팅한 [Deploy Amazon IVS Live Streams and Chat with Terraform](https://dev.to/aws/deploy-amazon-ivs-live-streams-and-chat-with-terraform-3cml)의 한국어 번역 포스트입니다.
> (This blog post is the Korean translation of Amazon IVS Engineer, [Kevin Eady](https://dev.to/kevineady)'s [Deploy Amazon IVS Live Streams and Chat with Terraform](https://dev.to/aws/deploy-amazon-ivs-live-streams-and-chat-with-terraform-3cml).)_

IaC(Infrastructure as Code)는 사용자 인터페이스를 통해 직접하기 보다는, 코드를 통해 서비스 인프라를 관리하고 프로비저닝하는 방법입니다. 여기에는 서버, 로드 밸런서, 데이터베이스, 네트워크 구성 등과 같은 리소스가 포함될 수 있습니다.

코드를 사용하여 인프라를 관리함으로써 많은 팀들이 인프라의 버전을 제어하고 리소스 프로비저닝 및 관리를 보다 쉽게 자동화할 수 있습니다. 이는 보다 일관되고 예측 가능한 배포가 가능하므로 많은 팀이 있고 복잡한 인프라가 있는 대규모 조직에서 특히 유용할 수 있습니다. 또한 필요한 경우 변경 사항을 쉽게 롤백할 수 있습니다.

[Hashicorp Terraform](https://www.terraform.io/)은 인프라를 안전하고 효율적으로 구축, 변경 및 버전 관리하기 위한 오픈 소스 도구입니다. Terraform은 [AWS Provider](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)를 통해 AWS 리소스를 비롯한 다양한 리소스 유형을 관리하는 데 사용할 수 있습니다. 이 블로그 포스트에서는 Terraform 설치, Amazon IVS(Interactive Video Service) 채널 생성, Amazon S3(Simple Storage Service)에 녹화하기, 채널 보호 활성화 및 IVS 채팅방 생성 과정을 안내합니다.

### Terraform 설치

시작하려면 [Terraform tutorial](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli#install-terraform)의 가이드에 따라 Terraform을 설치합니다. 이렇게 하면 `terraform` 커맨드라인 인터페이스(CLI)를 사용하여 HCL(HashiCorp Configuration Language)로 작성된 코드를 사용하여 인프라를 배포할 수 있습니다.

### AWS 계정 생성

Amazon IVS를 사용하려면 계정이 있어야 합니다. Amazon은 현재 [AWS Free Tier for Amazon IVS](https://aws.amazon.com/ivs/pricing/)에 따라 Amazon IVS 무료 평가판을 제공합니다(매월 기본 입력 5시간 및 SD 비디오 출력 100시간 - 그 외 다수).

> 프로덕션 애플리케이션에서 Amazon IVS를 실행하는 데 드는 비용이 궁금하십니까? [Amazon IVS Cost Estimator](https://ivs.rocks/calculator)를 확인하세요!

### AWS Terraform Provider 사용

Terraform은 Provider를 사용하여 API와의 상호 작용을 가능하게 합니다. [Terraform AWS Provider 설명서](https://registry.terraform.io/providers/hashicorp/aws/latest/docs)는 AWS 인증 및 리전 선택과 같은 Provider 구성에 대한 세부 정보를 제공합니다. 또한 자격 증명 사용에 대한 가이드와 모범 사례를 제공합니다.

## Amazon IVS에 Terraform 사용하기

Terraform은 다음 리소스 및 데이터 소스를 사용하여 AWS Terraform Provider 버전 `v4.40.0`부터 IVS를 완벽하게 지원합니다.

* Channels: [`aws_ivs_channel`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_channel)
* Playback Key Pairs: [`aws_ivs_playback_key_pair`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_playback_key_pair)
* Recording Configurations: [`aws_ivs_recording_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_recording_configuration)
* Stream Key: [`aws_ivs_stream_key`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_stream_key)

### IVS Channel 만들기

[`aws_ivs_channel`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_channel) 리소스는 S3에 저장하기 또는 재생 권한 부여 등 채널 속성을 구성하기 위한 많은 인수를 지원합니다.이 리소스는 Ingest endpoint([`ingest_endpoint`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_channel#ingest_endpoint))와 Playback URL([` playback_url`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivs_channel#playback_url)) 등의 출력 속성도 가지고 있습니다.

```terraform
terraform {
  required_version = ">= 0.12"
}
 
provider "aws" {
  region = "us-west-2"
}
 
resource "aws_ivs_channel" "example" {
  type = "BASIC"
}
 
data "aws_ivs_stream_key" "example" {
  channel_arn = aws_ivs_channel.example.arn
}
 
output "ingest_endpoint" {
  value = aws_ivs_channel.example.ingest_endpoint
}
 
output "stream_key" {
  value = data.aws_ivs_stream_key.example.value
}
 
output "playback_url" {
  value = aws_ivs_channel.example.playback_url
}
```

> 참고: AWS Free Tier에는 Basic 채널 유형만 적용됩니다.

`terraform apply`를 통해 이 구성을 적용할 때 Terraform은 인프라 Plan을 표시하고 구성을 적용하려면 "`yes`"라는 사용자 입력을 필요로 합니다. 이렇게 Plan을 적용하고 나면 출력변수들(ingest_endpoint, stream_key 및 playback_url)이 표시되는것을 볼 수 있습니다.

```console
➜  terraform apply
 
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
 + create
<= read (data resources)
 
Terraform will perform the following actions:
 
 # data.aws_ivs_stream_key.example will be read during apply
 # (config refers to values not yet known)
<= data "aws_ivs_stream_key" "example" {
     + arn         = (known after apply)
     + channel_arn = (known after apply)
     + id          = (known after apply)
     + tags        = (known after apply)
     + value       = (known after apply)
   }
 
 # aws_ivs_channel.example will be created
 + resource "aws_ivs_channel" "example" {
     + arn                         = (known after apply)
     + authorized                  = (known after apply)
     + id                          = (known after apply)
     + ingest_endpoint             = (known after apply)
     + latency_mode                = (known after apply)
     + name                        = (known after apply)
     + playback_url                = (known after apply)
     + recording_configuration_arn = (known after apply)
     + tags_all                    = (known after apply)
     + type                        = (known after apply)
   }
 
Plan: 1 to add, 0 to change, 0 to destroy.
 
Changes to Outputs:
 + ingest_endpoint = (known after apply)
 + playback_url    = (known after apply)
 + stream_key      = (known after apply)
 
Do you want to perform these actions?
 Terraform will perform the actions described above.
 Only 'yes' will be accepted to approve.
 
 Enter a value: yes
 
aws_ivs_channel.example: Creating...
aws_ivs_channel.example: Creation complete after 3s [id=arn:aws:ivs:us-west-2:326937407773:channel/EmVV0KxDONIR]
data.aws_ivs_stream_key.example: Reading...
data.aws_ivs_stream_key.example: Read complete after 1s [id=arn:aws:ivs:us-west-2:326937407773:stream-key/0Dy6pn6CQhMx]
 
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
 
Outputs:
 
ingest_endpoint = "a447f74b0a52.global-contribute.live-video.net"
playback_url = "https://a447f74b0a52.us-west-2.playback.live-video.net/api/video/v1/us-west-2.326937407773.channel.EmVV0KxDONIR.m3u8"
stream_key = "sk_us-west-xxxxxxxxxxxxx"
```

ingest_endpoint와 stream_key를 가지고 [Amazon IVS - Web Broadcast Tool](https://stream.ivs.rocks/)로 이동하여 스트리밍을 시작합니다. 페이지 하단 근처에 있는 "Open settings" 톱니바퀴 아이콘을 클릭합니다…

![Web Broadcast Tool - Open Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jitmb67z4alstmnmmxng.png)

... Ingest endpoint와 Stream key를 입력합니다.

![Web Broadcast Tool - Update Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0vp0nqmy3bivovh5jj0d.png)

"Save"을 클릭한 다음 "Start Streaming" 버튼을 클릭합니다.

![Web Broadcast Tool - Start Streaming](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfel7jlzdb551b7tanns.png)

... 그러면 당신의 스트림이 시작됩니다!

![Web Broadcast Tool - Live](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tptp6kzp68ulyfcj39gw.png)

스트림을 보려면 [Amazon IVS Player Tester](https://debug.ivsdemos.com/)로 이동하세요. 오른쪽 상단 모서리에 있는 톱니바퀴 아이콘을 클릭합니다.

![Player Tester - Open Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wqh507w7aktehd9ukqjf.png)

... 그리고 IVS Player를 추가합니다.

![Player Tester - Add IVS Player](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1thrbj69moksqkyu0f37.png)

재생 URL을 입력하고 "Load" 버튼을 클릭하면 라이브 스트림 재생이 시작됩니다.

![Player Tester - Live Stream](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n0v48vunw3eo7jluefof.png)

### S3에 레코드를 추가하기 위해 IVS 채널을 수정
이 예제에서는 Recording Configuration에서 사용할 새로운 S3 Bucket과 대상 Bucket 및 Thumbnail 속성을 지정하는 Recording Configuration을 생성하고, 이전에 생성한 채널에 Recording Configuration을 할당합니다. 이전 예제 설정을 수정해 봅시다.

```diff
provider "aws" {
   region = "us-west-2"
 }
+
+resource "aws_s3_bucket" "example" {
+  bucket_prefix = "tf-ivs-stream-archive-"
+  force_destroy = true
+}
+
+resource "aws_ivs_recording_configuration" "example" {
+  name = "tf-ivs-recording-configuration"
+  lifecycle {
+    create_before_destroy = true
+  }
+  thumbnail_configuration {
+    recording_mode = "INTERVAL"
+    target_interval_seconds = 30
+  }
+  destination_configuration {
+    s3 {
+      bucket_name = aws_s3_bucket.example.id
+    }
+  }
+}
+
 resource "aws_ivs_channel" "example" {
  type = "BASIC"
+  recording_configuration_arn = aws_ivs_recording_configuration.example.arn
 }
 
 data "aws_ivs_stream_key" "example" {
```

> 참고: [`create_before_destroy`](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle#create_before_destroy) lifecycle 옵션은 Recording Configuration이 삭제되어야 하는 설정 수정이 발생할 경우에 필요합니다. 왜냐하면, Recording Configuration은 in-place 수정이 불가하고 수정 사항이 존재하는 경우 재생성되어야 하기 때문입니다. Recording Configuration은 채널에서 사용하는 동안 삭제할 수 없으므로, 이 옵션(후속 수정 시)은 이전 Recording Configuration을 삭제하기 전에 새로운 Recording Configuration으로 채널을 업데이트합니다.

스트리밍하는 동안 IVS는 생성된 S3 Bucket 내부에 스트림을 저장합니다. 자세한 내용은 [Auto-Record to Amazon S3 - Amazon Interactive Video Service](https://docs.aws.amazon.com/ivs/latest/userguide/record-to-s3.html)를 참조하십시오.

> 참고: 라이브 상태인 채널은 수정할 수 없습니다. Terraform은 라이브 상태인 채널을 수정하려고 시도하는 경우 `Unable to perform: ivs:UpdateChannel while resource: <arn> is live`처럼 적절한 오류를 보고합니다.

### 재생 권한 부여 기능을 가지는 IVS Channel 만들기
이 예제에서는 [Amazon Key Management Service(KMS)](https://aws.amazon.com/kms/)를 사용하여 새로운 비대칭 키 쌍을 생성 후, 여기서 생성된 공개 키를 사용하여 새로운 Playback Key Pair를 생성하고, 마지막으로 인증 권한이 추가된 채널을 생성합니다:

```terraform
resource "aws_kms_key" "example" {
  description              = "KMS Key for IVS Playback"
  key_usage                = "SIGN_VERIFY"
  customer_master_key_spec = "ECC_NIST_P384"
}

data "aws_kms_public_key" "example" {
  key_id = aws_kms_key.example.key_id
}

resource "aws_ivs_playback_key_pair" "example" {
  name       = "tf-ivs-playback-key-pair"
  public_key = data.aws_kms_public_key.example.public_key_pem
}

resource "aws_ivs_channel" "example" {
  name       = "tf-ivs-playback-key-pair-example"
  authorized = true
}
```

인증 권한이 추가된 채널은 재생 URL에 JWT `token` URL 파라미터 추가를 요구합니다. [Generate and Sign Playback Tokens](https://docs.aws.amazon.com/ivs/latest/userguide/private-channels-generate-tokens.html)에서 자세한 내용을 확인하십시오.

다음은 서명된 URL을 생성하는 Node.js(v18) 콘솔 스크립트의 예제입니다. 이 스크립트는 `npm` 또는 `yarn`을 통해 설치된 다음의 노드 모듈을 필요로 합니다.

- [@aws-sdk/client-kms](https://www.npmjs.com/package/@aws-sdk/client-kms)
- [@aws-sdk/client-ivs](https://www.npmjs.com/package/@aws-sdk/client-ivs)
- [ecdsa-sig-formatter](https://www.npmjs.com/package/ecdsa-sig-formatter)

{% gist https://gist.github.com/KevinEady/101db59a8b1eaa59c5997edb208d404e file=create-playback-url-with-token.mjs %}

이 스크립트는 `keyId`, `channelArn`, 그리고 만료 시간을 나타내는 `expiresIn`을 인수로 사용합니다. Terraform 설정(`terraform show`를 사용하거나 설정 파일에 출력을 추가하여 확인 가능)을 통해서 생성된 인프라에 대해서 아래 스크립트를 실행하면 유효한 토큰이 추가된 재생 URL이 반환됩니다.

```
➜  node create-playback-url-with-token.mjs \
  --keyId 3df50d5f-054a-4f20-88c6-bb7a73306dd0 \
  --channelArn arn:aws:ivs:us-west-2:326937407773:channel/aVbMPCM9Il2x \
  --expiresIn 30

https://a447f74b0a52.us-west-2.playback.live-video.net/api/video/v1/us-west-2.326937407773.channel.aVbMPCM9Il2x.m3u8?token=eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJhd3M6Y2hhbm5lbC1hcm4iOiJhcm46YXdzOml2czp1cy13ZXN0LTI6MzI2OTM3NDA3NzczOmNoYW5uZWwvYVZiTVBDTTlJbDJ4IiwiYXdzOmFjY2Vzcy1jb250cm9sLWFsbG93LW9yaWdpbiI6IiIsImV4cCI6MTY3MzI3MzY5NCwiaWF0IjoxNjczMjczNjY0fQ.YAvlvVdO3rAq-7K3KHRPBvN1sU-JXJZ2963_thbaHBlBaYfyGYGAiqdJEN8XraEm3uc-h8NZiea8o0_XlOCHWIh9F1TGI1hSPqD7YY757C0ZF5cNsyBU49-sPbPvqpqa
```

## IVS Chat에 Terraform 사용하기
Terraform은 다음 리소스 및 데이터 소스를 사용하여 AWS Terraform Provider 버전 `v4.41.0`부터 IVS Chat을 완벽하게 지원합니다.

* Logging Configuration: [`aws_ivschat_logging_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivschat_logging_configuration)
* Room: [`aws_ivschat_room`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivschat_room)

### IVS Chat Room 만들기

IVS Chat Room은 [ivschat_room](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ivschat_room) 리소스를 사용하여 쉽게 생성할 수 있습니다.

```terraform
resource "aws_ivschat_room" "example" {
}
```

이렇게 생성된 Chat Room은 Amazon IVS Chat과 함께 사용할 수 있습니다. 좀 더 상세한 정보를 위해 [Getting Started with Amazon IVS Chat](https://docs.aws.amazon.com/ivs/latest/userguide/getting-started-chat.html)과 이전에 생성된 리소스들을 사용하여 채팅 기능을 검증하는 [Amazon IVS Chat Web Demo](https://github.com/aws-samples/amazon-ivs-chat-web-demo)도 살펴보시기 바랍니다.

### Message Handler가 추가된 IVS Chat Room 만들기
[IVS Chat Message Review Handler](https://docs.aws.amazon.com/ivs/latest/userguide/chat-message-review-handler.html)는 채팅 메시지 전송 전에 메시지 수정 또는 메시지 전송 거부를 가능하도록 하는 Lambda Function입니다. 이 예제에서는 Lambda Function, IVS Chat이 Lambda Function을 실행가능하도록 하는 IAM Role, 그리고 여기서 생성한 Lambda Function을 Message Review Handler로 사용하는 IVS Chat Room을 생성합니다.

```js
// index.js

/** IVS Chat message review handler */
exports.handler = async function ({ Content }) {
    return {
        ReviewResult: "ALLOW",
        Content: `${Content} - edited by Lambda`
    };
}
```

```terraform
# main.tf

data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

resource "aws_iam_role" "example" {
  name               = "tf-ivschat-message-handler-role"
  assume_role_policy = <<EOF
{
	"Version": "2012-10-17",
	"Statement": [{
		"Effect": "Allow",
		"Action": ["sts:AssumeRole"],
		"Principal": {"Service": "lambda.amazonaws.com"}
	}]
}
EOF
}

data "archive_file" "message_review_handler" {
  type        = "zip"
  source_file = "${path.module}/index.js"
  output_path = "${path.module}/lambda-handler.zip"
}

resource "aws_lambda_function" "example" {
  filename         = data.archive_file.message_review_handler.output_path
  function_name    = "tf-ivschat-message-handler"
  role             = aws_iam_role.example.arn
  source_code_hash = data.archive_file.message_review_handler.output_base64sha256
  runtime          = "nodejs18.x"
  handler          = "index.handler"
}

resource "aws_lambda_permission" "example" {
  action         = "lambda:InvokeFunction"
  function_name  = aws_lambda_function.example.function_name
  principal      = "ivschat.amazonaws.com"
  source_account = data.aws_caller_identity.current.account_id
  source_arn     = "arn:aws:ivschat:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:room/*"
}

resource "aws_ivschat_room" "example" {
  name       = "tf-ivschat-room"
  depends_on = [aws_lambda_permission.example]

  message_review_handler {
    uri             = aws_lambda_function.example.arn
    fallback_result = "ALLOW"
  }
}
```

### Logging이 가능한 IVS Chat Room 만들기

IVS Chat은 S3 Bucket 또는 CloudWatch와 같은 다양한 유형의 대상에 채팅 메시지를 Logging할 수 있도록 지원합니다. 이 예제에서는 Logging Configuration에 사용할 S3 Bucket을 생성하고, 이전에 생성한 Room에 Logging Configuration을 할당합니다:

```terraform
resource "aws_s3_bucket" "example" {
  bucket_prefix = "tf-ivschat-logging-"
  force_destroy = true
}

resource "aws_ivschat_logging_configuration" "example" {
  name = "tf-ivschat-logging-configuration"
  destination_configuration {
    s3 {
      bucket_name = aws_s3_bucket.example.id
    }
  }
}

resource "aws_ivschat_room" "example" {
  name                              = "tf-ivschat-room"
  logging_configuration_identifiers = [aws_ivschat_logging_configuration.example.arn]
}
```

### 마무리
Terraform을 사용해서도, 개발자는 설정 파일을 생성해서 IVS 및 IVS Chat 리소스의 배포를 관리할 수 있습니다. IaC를 사용하면 개발팀에 버전 제어, 공동 작업, 재사용성 및 재해 복구와 같은 여러 가지 이점을 제공할 수 있습니다. Amazon IVS 및 IVS Chat과 관련된 모든 기능을 살펴보려면 [Amazon IVS 사용 설명서](https://docs.aws.amazon.com/ivs/latest/userguide/what-is.html)를 살펴보십시오.