목차
4 장

AWS CLI와 SDK 셋업

aws cli v2 설치와 aws configure, 프로파일과 자격 증명 파일, boto3 / aws-sdk-js 같은 SDK의 용도, 그리고 자격 증명 체인이 흐르는 순서까지 — 콘솔 밖에서 AWS와 일하는 셋업을 정리합니다.

2장 IAM에서 만든 사용자의 액세스 키, 그리고 3장 비용 관리에서 켠 결제 알림이 준비됐습니다. 이제 콘솔 밖에서 AWS와 일할 차례입니다.

콘솔은 학습이나 일회성 작업에 좋지만 반복 / 자동화 / 정밀한 작업에는 한계가 옵니다. 그때 두 가지가 등장합니다. 하나는 AWS CLI로, 터미널에서 aws s3 cp ... 같은 명령으로 AWS를 부리는 도구입니다. 다른 하나는 SDK로, 코드 안에서 AWS를 부르는 라이브러리(Python의 boto3, JS의 aws-sdk 등)입니다.

본 챕터는 그 둘의 셋업과, 그 뒤에서 자격이 흐르는 순서(credential chain)를 정리합니다. 여기서 잡는 자격 증명 체인은 5장 CloudShell과 SSO의 SSO 로그인까지 그대로 이어집니다.

AWS CLI v2 설치 #

CLI는 v1과 v2가 있습니다. v2가 표준입니다. v1은 더 이상 쓰지 않습니다. v2의 차이는 다음과 같습니다.

  • 단일 실행 파일(Python 환경 의존 없음)
  • IAM Identity Center (SSO) 네이티브 지원(5장 CloudShell과 SSO)
  • 더 빠른 출력과 더 풍부한 자동완성
  • aws configure import 같은 새 명령

macOS #

설치 (Homebrew)
brew install awscli

또는 공식 pkg로 설치합니다.

설치 (공식 pkg)
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /

Linux #

설치 (x86_64)
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

Windows #

winget 또는 MSI 인스톨러를 씁니다.

winget
winget install -e --id Amazon.AWSCLI

설치 확인 #

버전 확인
aws --version
# aws-cli/2.x.x Python/3.x.x ...

2.x.x가 안 보이면 which aws로 v1 잔재를 확인한 뒤 제거합니다.

aws configure — 자격 등록 #

CLI가 설치되었으면 2장 IAM의 사용자 액세스 키를 등록합니다.

기본 프로파일 설정
aws configure
# AWS Access Key ID [None]: AKIA...
# AWS Secret Access Key [None]: wJal...
# Default region name [None]: ap-northeast-2
# Default output format [None]: json

이 네 값이 두 파일에 나뉘어 저장됩니다.

저장 위치
~/.aws/credentials   # 키 (민감)
~/.aws/config        # region / output / role / 등

~/.aws/credentials의 모양 #

~/.aws/credentials
[default]
aws_access_key_id = AKIA...
aws_secret_access_key = wJal...

~/.aws/config의 모양 #

~/.aws/config
[default]
region = ap-northeast-2
output = json

프로파일 — 여러 자격을 동시에 #

여러 계정 / 환경 / 역할을 다루면 default 하나로는 부족합니다. 프로파일로 여러 자격을 분리합니다.

프로파일 추가 #

dev / prod 두 프로파일
aws configure --profile dev
aws configure --profile prod
결과 — ~/.aws/credentials
[default]
aws_access_key_id = AKIA...

[dev]
aws_access_key_id = AKIA-DEV-...
aws_secret_access_key = ...

[prod]
aws_access_key_id = AKIA-PROD-...
aws_secret_access_key = ...

프로파일 사용 #

세 가지 방법이 있습니다.

1) --profile 플래그
aws s3 ls --profile prod
2) 환경 변수
export AWS_PROFILE=prod
aws s3 ls
3) 셸 함수 (.zshrc / .bashrc)
function awsenv() {
  export AWS_PROFILE=$1
  echo "AWS_PROFILE=$AWS_PROFILE"
}
# 사용: awsenv prod

운영에서는 환경 변수와 함께 셸 프롬프트에 현재 프로파일을 표시하는 패턴이 흔합니다.

셸 프롬프트에 현재 프로파일 표시 #

AWS_PROFILE을 프롬프트에 띄우면 사고가 줍니다.

zsh 예 (~/.zshrc)
PROMPT='%n@%m %1~ ${AWS_PROFILE:+[aws:$AWS_PROFILE]} %# '

운영용 터미널 색을 다르게 하는 패턴도 흔합니다. prod 프로파일일 때 빨간색, dev 일 때 초록처럼 두는 식입니다.

Role 사용 — assume-role 흐름 #

2장 IAM에서 다룬 역할(Role)을 CLI에서 빌리는 흐름입니다. 멀티 어카운트 셋업의 표준 패턴입니다.

~/.aws/config — role 프로파일
[profile prod]
role_arn = arn:aws:iam::222222222222:role/AdminRole
source_profile = default
mfa_serial = arn:aws:iam::111111111111:mfa/curtis
region = ap-northeast-2

이 프로파일을 쓰면 다음 순서로 작동합니다.

  1. default 프로파일의 자격으로 STS AssumeRole을 호출합니다.
  2. MFA 코드를 묻습니다(mfa_serial이 있으면).
  3. 임시 자격을 받아 명령에 사용합니다.
  4. 1시간 동안 캐시해 재사용합니다.
사용
aws s3 ls --profile prod
# Enter MFA code for arn:aws:iam::111111111111:mfa/curtis: 123456
# (이후 1 시간 캐시)

CI 환경에서는 5장 CloudShell과 SSO의 IAM Identity Center (SSO)가 더 매끈합니다.

환경 변수 — CI와 컨테이너의 자격 #

~/.aws/credentials가 없는 환경(CI, 컨테이너, 임시 셸)에서는 환경 변수를 씁니다.

변수무엇
AWS_ACCESS_KEY_ID액세스 키
AWS_SECRET_ACCESS_KEY비밀 키
AWS_SESSION_TOKEN임시 자격일 때 함께 (STS / SSO)
AWS_REGION 또는 AWS_DEFAULT_REGION리전
AWS_PROFILE프로파일 이름
환경 변수로 임시 셸
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_REGION=ap-northeast-2
aws s3 ls

자격 증명 체인 — 어디서 자격을 찾는가 #

CLI와 SDK가 자격을 찾는 순서가 정해져 있습니다. 이걸 모르면 “왜 이 키로 도는 거지?” 디버깅에 시간을 버립니다.

자격 증명 체인 (위에서 아래로)
1. 명령행 옵션  (--profile, --region 등)
2. 환경 변수    (AWS_ACCESS_KEY_ID 등)
3. 어시스턴트 파일 (CLI Web Identity Token, Container Credentials)
4. ~/.aws/credentials의 default 또는 지정 프로파일
5. ~/.aws/config의 프로파일 (role_arn, sso_session 등)
6. EC2 / ECS / Lambda의 인스턴스 / 컨테이너 자격

EC2 안에서 aws s3 ls가 자격 없이 작동하는 이유는 6단계의 인스턴스 메타데이터가 잡아 주기 때문입니다(2장 IAM의 인스턴스 프로파일).

어떤 자격이 쓰이는지 확인 #

현재 자격 확인
aws sts get-caller-identity
# {
#   "UserId": "AIDA...",
#   "Account": "111111111111",
#   "Arn": "arn:aws:iam::111111111111:user/curtis"
# }

이 한 줄이 디버깅의 첫 단계입니다. 어느 사용자 / 어느 계정으로 도는지가 나옵니다.

자주 쓰는 CLI 명령 #

출력 포맷 #

--output 옵션
aws ec2 describe-instances --output json   # 기본
aws ec2 describe-instances --output table  # 사람용
aws ec2 describe-instances --output text   # grep / awk 용
aws ec2 describe-instances --output yaml   # YAML

–query — JMESPath로 골라내기 #

JSON 출력이 길어서 grep으로는 한계가 옵니다. --query로 필요한 부분만 골라냅니다.

실행 중인 인스턴스 ID와 타입만
aws ec2 describe-instances \
  --query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,InstanceType]' \
  --output table

JMESPath 문법은 처음에는 어렵지만 자주 쓰는 패턴 5~10개만 외우면 일상 작업이 빨라집니다.

패턴의미
[]배열 평탄화
[?key==\value`]`필터
[].field필드 꺼내기
[].[a,b,c]여러 필드를 새 배열로
length(@)길이
sort_by(@, &date)정렬

자주 쓰는 명령들 #

신원 / 환경
aws sts get-caller-identity
aws configure list
aws configure list-profiles
S3
aws s3 ls                              # 모든 버킷
aws s3 ls s3://my-bucket/              # 버킷 안
aws s3 cp file.txt s3://my-bucket/     # 업로드
aws s3 sync ./local s3://my-bucket/    # 폴더 동기화
aws s3 rm s3://my-bucket/file.txt      # 삭제
aws s3 presign s3://my-bucket/file.pdf --expires-in 3600
EC2
aws ec2 describe-instances
aws ec2 start-instances --instance-ids i-...
aws ec2 stop-instances --instance-ids i-...
aws ec2 describe-regions --query 'Regions[].RegionName'
IAM
aws iam list-users
aws iam get-user --user-name curtis
aws iam list-attached-user-policies --user-name curtis
aws iam create-access-key --user-name curtis

SDK — 코드 안의 AWS #

CLI가 터미널이라면 SDK는 코드입니다. 같은 자격 체인을 공유합니다.

Python — boto3 #

설치
pip install boto3
기본 사용
import boto3

s3 = boto3.client("s3")
res = s3.list_buckets()
for b in res["Buckets"]:
    print(b["Name"])

자격은 자동으로 자격 체인에서 찾습니다 — ~/.aws/credentials, 환경 변수, EC2 인스턴스 프로파일 등입니다.

명시적 프로파일 / 리전 #

명시 지정
session = boto3.Session(profile_name="prod", region_name="ap-northeast-2")
s3 = session.client("s3")

리소스 vs 클라이언트 #

boto3에는 두 인터페이스가 있습니다.

client — 저수준, AWS API 그대로
s3 = boto3.client("s3")
res = s3.list_objects_v2(Bucket="my-bucket")
for obj in res.get("Contents", []):
    print(obj["Key"])
resource — 객체 지향, 더 짧음 (점점 deprecated 되는 추세)
s3 = boto3.resource("s3")
for obj in s3.Bucket("my-bucket").objects.all():
    print(obj.key)

현대 boto3는 client를 권장합니다. resource는 일부 서비스만 지원하고, 새로운 서비스는 더 이상 추가되지 않습니다.

Pagination — 자주 만나는 함정 #

list_objects_v2는 한 번에 최대 1000 개입니다. 그 이상은 paginator로 받습니다.

paginator로 모든 객체
s3 = boto3.client("s3")
paginator = s3.get_paginator("list_objects_v2")
for page in paginator.paginate(Bucket="my-bucket"):
    for obj in page.get("Contents", []):
        print(obj["Key"])

JavaScript / TypeScript — aws-sdk v3 #

v2는 deprecated입니다. v3로 갑니다.

설치
npm install @aws-sdk/client-s3
기본 사용
import { S3Client, ListBucketsCommand } from "@aws-sdk/client-s3";

const client = new S3Client({ region: "ap-northeast-2" });
const res = await client.send(new ListBucketsCommand({}));
for (const b of res.Buckets ?? []) {
  console.log(b.Name);
}

v3의 특징은 다음과 같습니다.

  • 모듈식 — 필요한 서비스만 import (번들 크기 감소)
  • 트리 셰이킹 친화
  • 모든 호출이 client.send(new XxxCommand(...)) 패턴

Go — aws-sdk-go-v2 #

설치
go get github.com/aws/aws-sdk-go-v2/aws
go get github.com/aws/aws-sdk-go-v2/config
go get github.com/aws/aws-sdk-go-v2/service/s3
기본 사용
package main

import (
    "context"
    "fmt"

    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    ctx := context.Background()
    cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("ap-northeast-2"))
    if err != nil {
        panic(err)
    }
    client := s3.NewFromConfig(cfg)
    res, err := client.ListBuckets(ctx, &s3.ListBucketsInput{})
    if err != nil {
        panic(err)
    }
    for _, b := range res.Buckets {
        fmt.Println(*b.Name)
    }
}

Go 트랙의 컨벤션대로 context 우선과 명시적 에러를 따릅니다.

자동완성 켜기 #

탭 자동완성을 켜면 CLI가 훨씬 부드러워집니다.

zsh
autoload bashcompinit && bashcompinit
autoload -Uz compinit && compinit
complete -C "$(which aws_completer)" aws
bash
complete -C "$(which aws_completer)" aws

.zshrc.bashrc에 넣고 새 셸을 엽니다. 이제 aws s3 <TAB> 하면 명령과 옵션이 보입니다.

자주 만나는 함정 #

  • ~/.aws/credentials를 git에 커밋 — 가장 위험한 사고입니다. 반드시 .gitignore.aws/ 또는 글로벌 gitignore에 넣습니다. 그리고 액세스 키는 가능한 한 환경 변수 / SSO로 두고 파일에 두지 않는 것이 점점 표준입니다.
  • 잘못된 프로파일에서 운영 명령AWS_PROFILE=dev로 일하다가 명령에 --profile prod가 따로 적혀 있어 prod 버킷이 보이는 경우가 있습니다. 출처를 명시하고 aws sts get-caller-identity로 먼저 점검하는 것이 답입니다.
  • 자격 체인 디버깅 — “환경 변수에 키를 넣었는데 옛날 키로 도네” 라면 자격 체인 1 단계(명령행 --profile)가 우선이거나, 셸이 export를 못 받았을 가능성입니다. aws sts get-caller-identity로 먼저 진단합니다.
  • v1 잔재aws --version이 1.x 라면(특히 macOS / Linux의 pip install awscli 흔적) v1 잔재입니다. v1과 v2가 동시에 PATH에 있으면 의도하지 않은 v1이 실행되니, which aws로 확인하고 제거합니다.
  • 페이지네이션 누락list_* API는 거의 모두 페이지네이션이 있습니다. 첫 페이지만 처리하고 끝내면 1000번째 이후 데이터가 누락됩니다. paginator 또는 NextToken 루프를 씁니다.
  • SDK의 자격을 코드에 넣기 — 아래처럼 코드에 키를 넣으면 git으로 노출되어 사고로 이어집니다.
안 됨
boto3.client("s3", aws_access_key_id="AKIA...", aws_secret_access_key="...")

자격은 환경 / 프로파일 / 인스턴스 프로파일에서 받습니다.

연습문제 #

  1. §“자격 증명 체인"의 여섯 단계를 보지 않고 순서대로 적어 보세요. 그런 다음, EC2 안에서 aws s3 ls가 키 없이 작동하는 이유가 몇 번째 단계인지 2장 IAM의 인스턴스 프로파일과 연결해 설명해 보세요.
  2. §“Role 사용 — assume-role 흐름"의 role_arn + source_profile + mfa_serial 프로파일이 2장 IAM의 Trust Policy와 Permission Policy 중 어느 흐름을 재현하는지 한 단락으로 설명해 보세요.
  3. aws ec2 describe-instances의 출력에서 실행 중인 인스턴스의 ID와 타입만 뽑는 --query 표현을 §”–query"의 표를 참고해 직접 작성해 보세요.

한 줄 요약: AWS CLI v2와 SDK는 같은 자격 증명 체인을 공유하며, 자격은 명령행 → 환경 변수 → 파일 → 인스턴스 프로파일 순으로 찾는다. aws configure는 자격을 ~/.aws/credentials~/.aws/config 두 파일에 나눠 저장하고, 프로파일로 여러 계정을 분리한다. 키를 코드나 git에 넣지 않고 aws sts get-caller-identity로 먼저 신원을 확인하는 것이 디버깅과 사고 예방의 기본이다.

다음 챕터 #

로컬 셋업이 끝났습니다. 그런데 다른 사람의 노트북이나 회사 임시 환경에서도 같은 CLI가 필요할 때가 있고, 멀티 어카운트가 시작되면 로그인 자체가 더 정교해져야 합니다. 다음 5장 CloudShell과 SSO에서는 콘솔 안의 브라우저 터미널 CloudShell과, 멀티 어카운트의 표준 로그인이 된 IAM Identity Center (SSO) 셋업을 정리합니다.

X