AWS 기초 #4 AWS CLI와 SDK 셋업
#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 #
brew install awscli또는 공식 pkg 설치:
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /Linux #
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/installWindows #
winget 또는 MSI 인스톨러:
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의 모양
#
[default]
aws_access_key_id = AKIA...
aws_secret_access_key = wJal...~/.aws/config의 모양
#
[default]
region = ap-northeast-2
output = json프로파일: 여러 자격을 동시에 #
여러 계정 / 환경 / 역할을 다루면 default 하나로는 부족합니다. 프로파일로 여러 자격을 분리합니다.
프로파일 추가 #
aws configure --profile dev
aws configure --profile prod[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 = ...프로파일 사용 #
세 가지 방법.
aws s3 ls --profile prodexport AWS_PROFILE=prod
aws s3 lsfunction awsenv() {
export AWS_PROFILE=$1
echo "AWS_PROFILE=$AWS_PROFILE"
}
# 사용: awsenv prod운영에선 환경 변수 + 셸 프롬프트에 현재 프로파일 표시 패턴이 흔합니다.
셸 프롬프트에 현재 프로파일 표시 #
AWS_PROFILE을 프롬프트에 띄우면 사고가 줍니다.
PROMPT='%n@%m %1~ ${AWS_PROFILE:+[aws:$AWS_PROFILE]} %# '운영용 터미널 색을 다르게 하는 패턴도 흔합니다. prod 프로파일일 때 빨간색, dev일 때 초록색으로 두는 식입니다.
Role 사용: assume-role 흐름 #
#2에서 다룬 역할 (Role)을 CLI에서 빌리는 방법입니다. 멀티 어카운트 셋업의 표준 패턴입니다.
[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이 프로파일을 쓰면:
default프로파일의 자격으로 STS AssumeRole 호출- MFA 코드 묻기 (mfa_serial이 있으면)
- 임시 자격을 받아 명령에 사용
- 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 명령 #
출력 포맷 #
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로 필요한 값만 골라냅니다:
aws ec2 describe-instances \
--query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,InstanceType]' \
--output tableJMESPath 문법은 처음엔 어렵지만 자주 쓰는 패턴 5~10개만 외우면 일상 작업이 빨라집니다.
| 패턴 | 의미 |
|---|---|
[] | 배열 평탄화 |
[?key==\value`]` | 필터 |
[].field | 필드 꺼내기 |
[].[a,b,c] | 여러 필드를 새 배열로 |
length(@) | 길이 |
sort_by(@, &date) | 정렬 |
자주 쓰는 명령들 #
aws sts get-caller-identity
aws configure list
aws configure list-profilesaws 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 3600aws ec2 describe-instances
aws ec2 start-instances --instance-ids i-...
aws ec2 stop-instances --instance-ids i-...
aws ec2 describe-regions --query 'Regions[].RegionName'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 curtisSDK: 코드 안의 AWS #
CLI가 터미널에서 쓰는 도구라면 SDK는 코드 안에서 쓰는 도구입니다. 같은 자격 체인을 공유합니다.
Python: boto3 #
pip install boto3import 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에는 두 인터페이스가 있습니다.
s3 = boto3.client("s3")
res = s3.list_objects_v2(Bucket="my-bucket")
for obj in res.get("Contents", []):
print(obj["Key"])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로 가져옵니다.
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-s3import { 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/s3package 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가 훨씬 부드러워집니다.
autoload bashcompinit && bashcompinit
autoload -Uz compinit && compinit
complete -C "$(which aws_completer)" awscomplete -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번째 이후가 누락됩니다. paginator나 NextToken 루프로 처리합니다.
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) 셋업을 정리하겠습니다.