Unable to load credentials error in AWS ECS

2 분 소요


0. 들어가면서

AWS ECS(elastic container service) 클러스터에 서비스를 배포할 때 발생한 에러와 해결 방법에 대해 정리했다.

1. Problem context

DynamoDB를 사용하는 애플리케이션을 ECS 클러스터에 서비스를 배포할 때 다음과 같은 에러를 만났다.

software.amazon.awssdk.core.exception.SdkClientException: Unable to load credentials from any of the providers in the chain AwsCredentialsProviderChain
(credentialsProviders=[SystemPropertyCredentialsProvider(), EnvironmentVariableCredentialsProvider(), WebIdentityTokenCredentialsProvider(), ProfileCredentialsProvider(profileName=default, profileFile=ProfileFile(sections=[])), ContainerCredentialsProvider(), InstanceProfileCredentialsProvider()]) : 
[SystemPropertyCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., 
EnvironmentVariableCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., 
WebIdentityTokenCredentialsProvider(): Either the environment variable AWS_WEB_IDENTITY_TOKEN_FILE or the javaproperty aws.webIdentityTokenFile must be set., 
ProfileCredentialsProvider(profileName=default, profileFile=ProfileFile(sections=[])): Profile file contained no credentials for profile 'default': ProfileFile(sections=[]), 
ContainerCredentialsProvider(): Cannot fetch credentials from container - neither AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variables are set., 
InstanceProfileCredentialsProvider(): Failed to load credentials from IMDS.]

...

단순히 로그만 봤을 땐 애플리케이션에서 사용하는 DynamoDB 클라이언트 객체에 필요한 자격 증명(credential)이 설정되지 않은 것이 문제로 보인다.

Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId).

실제 운영 환경에서 사용 중인 DynamoDB 클라이언트 객체에는 별도로 자격 증명을 설정하고 있지 않다.

package com.example.demo.config

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.dynamodb.DynamoDbClient

@Configuration
class DynamoDbConfig {

    @Bean
    fun dynamoDbClient(): DynamoDbClient {
        return DynamoDbClient.builder()
            .region(Region.AP_NORTHEAST_1)
            .build()
    }
}

2. Solve the problem

ECS에 DynamoDB를 사용하는 서비스를 배포해 본 경험이 있기 때문에 코드에 문제가 없을 것이라고 확신했다. 그렇다면 어디에 문제가 있었을까? ECS 클러스터에 서비스를 배포할 때 필요한 태스크 정의(task definition)을 만들 때 권한과 관련이 있다. 태스크 정의를 만들 떄 두 개의 권한을 설정할 수 있다.

  • Task role
  • Task execution role


태스크 롤(task role)은 ECS 태스크가 실행 중 AWS 리소스에 접근하는 경우 필요한 역할이다. 즉, 컨테이너 내부에서 실행되는 우리가 개발한 애플리케이션이 S3, DynamoDB, Secret Manager 같은 AWS 리소스에 접근할 때 필요한 역할이다. 예를 들어, ECS 태스크가 아래와 같은 기능이 필요하다면 태스크 롤 설정이 필요하다.

  • S3 버킷에서 파일 읽기/쓰기
  • DynamoDB 테이블 접근
  • Secrets Manager에서 비밀 정보 가져오기

태스크 실행 롤(task execution role)은 AWS ECS 에이전트(agent)가 태스크를 실행하고 관리하기 할 때 필요한 AWS 리소스에 접근할 때 필요한 역할이다. 에이전트란 Fargate 플랫폼(혹은 ECS 자체)를 의미한다. 예를 들어, ECS 에이전트가 클러스터에 서비스를 배포할 때 필요한 기능들은 다음과 같다.

  • ECR(elastic container registry)에서 도커 이미지를 가져오기
  • CloudWatch에 로그 전송

위 설명을 보면 살펴보면 애플리케이션에서 발생하는 원인을 예상할 수 있다. 문제가 발생한 이유는 서비스를 배포할 때 사용한 태스크 정의에 태스크 롤 설정이 없기 때문이다. 다음과 같이 적절한 IAM 롤을 만든 후 ECS 태스크 정의를 업데이트한다.

  • IAM 역할에 ecs-task-dynamodb-role라는 이름으로 롤을 만든 후 이를 설정한다.


IAM 역할에 만든 ecs-task-dynamodb-role에 DynamoDB 테이블 접근을 위한 AmazonDynamoDBFullAccess 권한을 설정한다.

REFERENCE

댓글남기기