AWS 기초 #4 AWS CLI와 SDK 셋업

8 분 소요

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

콘솔은 학습 / 일회성 작업에 좋지만 반복 / 자동화 / 정밀한 작업에는 한계가 옵니다. 그래서 두 가지가 등장합니다.

  • AWS CLI. 터미널에서 aws s3 cp ... 같은 명령으로 AWS를 부리는 도구
  • SDK. 코드 안에서 AWS를 부르는 라이브러리 (boto3 for Python, aws-sdk for JS, …)

이 글은 그 둘의 셋업과, 그 뒤에서 자격 증명이 흘러가는 순서(credential chain)를 정리하겠습니다.

AWS CLI v2 설치 #

CLI는 v1과 v2가 있습니다. v2가 표준이므로 v1은 더 이상 쓰지 마세요. v2의 차이:

  • 단일 실행 파일 (Python 환경 의존 없음)
  • IAM Identity Center (SSO) 네이티브 지원 (#5)
  • 더 빠른 출력 / 더 풍부한 자동완성
  • 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에서 다룬 역할 (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의 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의 인스턴스 프로파일).

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

현재 자격 확인
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> 하면 명령 / 옵션이 보입니다.

자주 만나는 함정 #

1) ~/.aws/credentials를 git에 커밋 #

가장 위험한 사고입니다. .aws/는 **반드시 .gitignore**나 글로벌 gitignore에 넣습니다. 그리고 액세스 키는 가능하면 환경 변수 / SSO로 두고, 파일에 두지 않는 것이 점점 표준이 되고 있습니다.

2) 잘못된 프로파일에서 운영 명령 #

AWS_PROFILE=dev로 일하다가 aws s3 rb s3://...-prod를 칩니다. 잠깐, 환경 변수가 dev인데 왜 prod 버킷이 보이지? 사실 --profile prod가 따로 적혀 있었던 것입니다. 출처 명시성과 aws sts get-caller-identity 첫 점검이 답입니다.

3) 자격 체인 디버깅 #

“환경 변수에 키를 넣었는데 옛날 키로 도네” 싶을 때가 있습니다. 자격 체인 1단계(명령행 --profile)가 우선이기 때문입니다. 또는 셸이 export를 못 받았을 가능성도 있습니다. aws sts get-caller-identity로 먼저 진단합니다.

4) v1 잔재 #

aws --version이 1.x 면 (특히 macOS / Linux의 pip install awscli 흔적) v1 잔재. v1 / v2가 동시에 PATH에 있으면 의도하지 않은 v1 실행. which aws로 확인하고 제거.

5) 페이지네이션 누락 #

list_* API는 거의 모두 페이지네이션이 있습니다. 첫 페이지만 처리하고 끝내면 운영 데이터의 1000번째 이후가 누락됩니다. paginatorNextToken 루프로 처리합니다.

6) SDK의 자격을 코드에 넣기 #

안 됨
boto3.client("s3", aws_access_key_id="AKIA...", aws_secret_access_key="...")

자격은 환경 변수 / 프로파일 / 인스턴스 프로파일에서 가져옵니다. 코드에 넣는 순간 git에 올라가고, 노출되고, 사고로 이어집니다.

정리 #

이번 글에서 잡은 것:

  • AWS CLI v2 설치. Homebrew / curl / winget으로 설치합니다. v1은 더 이상 쓰지 않습니다.
  • **aws configure**로 자격을 등록하면 ~/.aws/credentials~/.aws/config 두 파일에 저장됩니다.
  • 프로파일로 여러 계정 / 환경을 분리합니다. --profile, AWS_PROFILE, 셸 함수를 씁니다.
  • Role 프로파일로 AssumeRole 흐름을 구성합니다. role_arn + source_profile + mfa_serial을 적습니다.
  • 환경 변수. CI / 컨테이너 / 임시 셸에서 씁니다. AWS_ACCESS_KEY_ID 외에 AWS_SESSION_TOKEN, AWS_REGION이 있습니다.
  • 자격 증명 체인. 명령행 → 환경 → 파일 → 인스턴스 프로파일 순입니다. aws sts get-caller-identity가 디버깅의 첫 단계입니다.
  • CLI 옵션. --output table/json/text, --query (JMESPath)를 씁니다.
  • SDK. boto3 / aws-sdk v3 / aws-sdk-go-v2가 자격 체인을 공유합니다. client / resource, paginator를 기억합니다.
  • 함정. credentials git 커밋, 프로파일 혼선, v1 잔재, pagination 누락, 코드에 키 넣기입니다.

다음: CloudShell과 SSO #

로컬 셋업이 끝났습니다. 그런데 다른 사람의 노트북 / 회사 임시 환경에서도 같은 CLI가 필요할 때가 있습니다. 또 멀티 어카운트가 시작되면 로그인 자체가 더 정교해져야 합니다.

#5 CloudShell과 IAM Identity Center (SSO)에서는 콘솔 안의 브라우저 터미널 (CloudShell)과, 멀티 어카운트의 표준 로그인이 된 IAM Identity Center (SSO) 셋업을 정리하겠습니다.

X