Jeric SkillsClaude Code 스킬 마켓플레이스
← 전체 스킬

aws-helper

v1.1.0

AWS를 조회하기 전에 실측 권한 캐시로 자격증명 프로파일을 고르고, 쓰기는 실행하지 않고 명령어와 롤백 방법만 제시

설치

호출 이름/aws-helper:aws-helper

aws-helper

AWS를 조회할 때 어떤 자격증명으로 볼지 먼저 정하고, 쓰기는 실행하지 않고 명령어만 넘기는 스킬.

왜 만들었나

~/.aws/credentials에 프로파일이 여러 개 쌓여 있고, 각각 권한이 좁게 갈려 있는 상황에서 출발했다. DynamoDB를 읽을 수 있는 프로파일과 테이블을 수정할 수 있는 프로파일이 다르고, 람다 코드를 받을 수 있는 프로파일은 IAM을 못 본다. 그래서 조회를 시킬 때마다 AccessDenied가 나고, 그게 권한이 없어서인지 프로파일을 잘못 골라서인지 매번 처음부터 다시 확인해야 했다.

"그럼 각 프로파일 권한을 읽어서 알려주면 되지 않나" 싶었는데, 실제로 확인해보니 모든 프로파일이 자기 IAM 정책 조회에서 AccessDenied였다.

[profile-a] AccessDenied ... ListAttachedUserPolicies
[profile-b] AccessDenied ... ListAttachedUserPolicies
[profile-c] AccessDenied ... ListAttachedUserPolicies

최소 권한으로 발급된 키라면 흔한 상황이다. 권한 목록을 물어보는 길이 막혀 있으니, 실제로 명령을 던져본 결과를 쌓는 것 말고는 방법이 없었다. 이 스킬은 그 누적 기록을 캐시로 관리해서, 쓸수록 프로파일 선택 질문이 줄어들도록 설계했다.

설계 결정

권한 정보는 캐시에 쌓고, 빈칸만 프로브한다. 매번 전 프로파일을 프로브하면 질문 하나당 수 초에서 십수 초가 붙는다. 캐시를 먼저 보고 기록이 없는 것만 던진다. 첫 회는 느리고 쓸수록 빨라진다.

"기록 없음"과 "권한 없음"을 구분한다. 캐시에 없다고 안 되는 게 아니다. 이걸 뭉개면 실제로는 가능한 조회를 "권한이 없습니다"라고 잘못 보고하게 된다.

캐시는 레포 밖(~/.claude/aws-profile-capabilities.json)에 둔다. 계정 ID와 사용자 ARN이 들어가므로 저장소에 올라가면 안 된다. 스킬 문서에도 실제 계정·프로파일명을 적지 않는다 — 런타임에 캐시를 읽으므로 문서에는 필요 없다.

확신할 때만 자동 선택한다. 후보가 딱 하나면 묻지 않고 진행하되 어떤 프로파일을 썼는지 항상 한 줄로 밝힌다 — 조회 결과의 신뢰도가 프로파일에 달려 있기 때문이다. 후보가 둘 이상이거나 기록이 없으면 묻는다.

쓰기 판정은 화이트리스트로 한다. describe-* get-* list-* 등 읽기로 확인된 것만 통과시키고 나머지는 전부 쓰기로 본다. 블랙리스트로 하면 새 AWS 명령이 생길 때마다 구멍이 뚫린다. 오탐(읽기를 쓰기로 봄)은 한 번 더 묻고 끝나지만 놓치면 되돌릴 수 없다.

쓰기는 실행하지 않는다. 명령어와 예상 영향, 롤백 방법을 만들어 넘기고 실행은 사람이 한다.

읽기 전용 Role 이 있으면 그걸 먼저 쓴다. IAM User 키는 권한이 제각각이라 읽기 조회 중에도 쓰기가 가능한 키를 쥐게 된다. MFA 로 assume 하는 읽기 전용 Role 이 있으면, 만료됐을 때 사용자에게 MFA 코드만 받아 비대화형 스크립트로 임시 자격증명을 갱신하고 그 프로파일로 조회한다. 코드를 기다리는 동안 다른 키로 우회하지 않는다 — 우회하면 Role 을 쓰는 의미가 없다. Role 이름·스크립트 경로는 캐시(read_role)에만 두고 문서에는 적지 않는다.

계정이 다르면 무조건 묻는다. 프로파일이 여러 계정에 걸쳐 있을 때 맥락만 보고 자동 선택하면 엉뚱한 환경을 보고 보고하게 된다.

사용 흐름

"이 람다 환경변수 뭐 들어있어?"
  → 캐시 조회: lambda:GetFunctionConfiguration 가능한 프로파일이 하나
  → "<프로파일명>으로 조회합니다" + 결과

"이 테이블 스트림 켜줘"
  → 쓰기 감지 → 실행하지 않음
  → 쓰기 권한이 확인된 프로파일 + 완성된 명령어 + 롤백 방법 제시

상태

첫 초안이고 실사용으로 검증되지 않았다. 캐시가 의도대로 누적되는지, 쓰기 판정에 오탐·누락이 없는지는 몇 번 써보면서 다듬어야 한다.

에이전트가 읽는 절차 — SKILL.md

설치하면 Claude가 실행 중에 참조하는 실제 문서다. 아래 내용이 그대로 동작을 결정한다.

AWS Helper

Overview

여러 자격증명 프로파일이 서로 다른 권한을 갖고 있을 때, 어떤 프로파일로 조회할지 먼저 정하고 AWS를 읽는다. 조회는 자유롭게 하되 쓰기는 절대 실행하지 않고 명령어만 만들어 넘긴다.

전제: 이 환경의 프로파일들은 자기 IAM 정책을 읽을 수 없다 (iam:ListAttachedUserPolicies 전부 AccessDenied). 그래서 권한 정보는 API 조회가 아니라 실제 명령을 던져본 결과를 누적한 캐시에서만 나온다.

When to Use

  • AWS 리소스를 조회·확인해야 할 때 (람다 설정, DynamoDB 스키마, S3 버킷, 로그 등)
  • 현재 AWS 구성을 파악해서 조언해야 할 때 ("이 람다 메모리 얼마로 잡는 게 좋냐")
  • 사용자가 쓰기를 요청했을 때 — 실행하지 않고 명령어를 만들어주기 위해 진입

Not for: AWS를 전혀 건드리지 않는 일반 코드 작업, 이미 이 세션에서 프로파일이 확정됐고 같은 서비스를 계속 조회하는 경우(캐시대로 진행).

권한 캐시

~/.claude/aws-profile-capabilities.json — 레포 밖에 둔다. 계정 ID와 사용자 ARN이 들어가므로 절대 커밋하지 않는다.

{
  "<프로파일명>": {
    "account": "<계정 ID>",
    "arn": "arn:aws:iam::<계정 ID>:user/<사용자명>",
    "region": "ap-northeast-2",
    "allow": ["dynamodb:DescribeTable", "dynamodb:Scan", "dynamodb:UpdateTable"],
    "deny": ["iam:ListAttachedUserPolicies", "firehose:ListDeliveryStreams"],
    "checked_at": "2026-09-02"
  }
}
  • allow / deny는 액션 단위로 기록한다 (서비스:액션). 서비스 단위로 뭉뜽그리지 않는다 — 같은 DynamoDB라도 Scan은 되고 UpdateTable은 안 되는 경우가 실제로 있다.
  • 캐시에 없는 액션은 "권한 없음"이 아니라 **"모름"**이다. 둘을 절대 혼동하지 않는다.

읽기 전용 Role 우선 (MFA assume)

캐시 최상위에 read_role 이 있으면, 읽기 조회는 IAM User 프로파일보다 이 Role 을 먼저 쓴다. 쓰기가 원천 차단된 Role 이라 오조작 위험이 없다.

"read_role": {
  "profile": "mfa-role-<RoleName>",
  "assume_cmd": "zsh ~/.aws/AssumeRole.zsh <MFA코드>"
}

assume_cmd 는 MFA 코드를 인자로 받아 STS 임시 자격증명을 profile 이름으로 ~/.aws/credentials 에 쓰는 비대화형 스크립트여야 한다. 대화형(read 프롬프트) 스크립트는 Claude 가 실행할 수 없다.

0단계 — 세션이 살아있는지 확인 (아래 절차 1번보다 먼저):

aws sts get-caller-identity --profile <read_role.profile> --query Arn --output text
결과 행동
ARN 출력 이 프로파일로 진행
ExpiredToken / could not be found MFA 코드를 요청하고 턴을 끝낸다 — "MFA 6자리 코드 알려주세요 (30초 안에 만료)" 한 줄만. AskUserQuestion 쓰지 않는다 (선택지가 아니라 값 입력)

코드를 받으면 assume_cmd 를 실행하고 → 0단계 명령으로 ARN 재확인 → 원래 조회 진행.

  • MultiFactorAuthentication failed / invalid MFA one time pass code → 코드 만료. 새 코드를 한 번만 다시 요청한다. 두 번 실패하면 멈추고 사용자에게 직접 ! source <스크립트> 실행을 안내한다
  • MFA 코드를 기다리는 동안 다른 프로파일로 우회 조회하지 않는다 — Role 을 쓰려는 이유(읽기 전용 보장)가 사라진다
  • 이 Role 에서 AccessDenied 가 난 액션만 기존 절차대로 IAM User 프로파일 중에서 고른다
  • read_role 이 캐시에 없으면 이 섹션을 건너뛴다

절차

1. 캐시를 읽는다. 파일이 없으면 부트스트랩:

for p in $(grep -E '^\[' ~/.aws/credentials | tr -d '[]'); do
  ( echo "$p -> $(aws sts get-caller-identity --profile "$p" --query Arn --output text 2>&1 | tail -1)" ) &
done; wait

전체 프로파일 병렬로 약 6초. 결과로 account / arn을 채운다.

2. 필요한 액션을 특정한다. "람다 환경변수 확인" → lambda:GetFunctionConfiguration.

3. 후보를 고른다.

캐시 상태 행동
allow에 그 액션이 있는 프로파일이 정확히 1개 자동 선택. <프로파일명>으로 조회합니다 한 줄만 명시하고 진행
후보가 2개 이상 AskUserQuestion
후보가 0개 (기록 없음) 4번 프로브 후 재판정
후보가 0개 (전부 deny) 프로파일 부족을 사용자에게 알린다. 임의로 다른 걸 시도하지 않는다

AskUserQuestion 선택지에는 캐시의 실측 내용을 그대로 넣는다 — 계정 번호, 확인된 액션, 막힌 액션. "아마 될 것 같다"를 쓰지 않는다.

4. 빈칸만 프로브한다. 그 액션 기록이 없는 프로파일에 한해, 부작용 없는 read 명령 1개를 병렬로 던져 결과를 캐시에 채운다. 이미 기록이 있으면 다시 던지지 않는다.

5. 실행하고 캐시에 기록한다. 성공 → allow, AccessDenied → deny, checked_at 갱신. 이 스킬 밖에서 실행한 aws 명령의 결과도 보이는 대로 기록한다.

읽기 / 쓰기 판정

화이트리스트 방식. 아래로 시작하는 서브커맨드만 읽기로 보고, 나머지는 전부 쓰기로 간주한다.

describe-*   get-*   list-*   scan   query   head-*   batch-get-*   lookup-*

예외로 읽기에 포함:

  • aws s3 ls, aws s3api head-object
  • aws logs filter-log-events, aws logs tail
  • aws sts get-caller-identity
  • aws s3 cp <s3://...> <로컬경로> — 다운로드 방향만. 업로드는 쓰기다

애매하면 쓰기로 처리한다. 오탐(읽기를 쓰기로 봄)은 한 번 더 묻고 끝나지만, 반대는 되돌릴 수 없다.

쓰기 요청이 들어왔을 때

실행하지 않는다. 대신 이 세 가지를 낸다.

  1. 쓰기 권한이 확인된 프로파일 — 캐시 기준. 없으면 "확인된 프로파일 없음"이라고 쓴다
  2. 그대로 복붙할 명령어 — --profile, --region 포함한 완성형
  3. 예상 영향과 롤백 방법 — 무엇이 바뀌고, 잘못됐을 때 어떻게 되돌리는지

콘솔에서 하는 게 나은 작업(IAM 정책 편집 등)이면 그렇게 말한다.

계정 분리 가드

프로파일이 여러 AWS 계정에 걸쳐 있을 수 있다. 캐시의 account 필드로 판별한다.

후보에 서로 다른 계정이 섞이면 자동 선택하지 않고 반드시 묻는다. 대화 맥락이 한쪽을 가리켜도 마찬가지다 — 계정을 잘못 짚으면 엉뚱한 환경을 보고 보고하게 된다.

같은 IAM 사용자를 가리키는 프로파일(흔한 예: default가 다른 프로파일의 별칭)은 캐시에서 arn이 같은 것으로 판별해 후보로 중복 나열하지 않는다.

Common Mistakes

  • 캐시에 없는 걸 "권한 없음"으로 단정 — 기록 없음은 모름이다. 프로브하거나 묻는다
  • AccessDenied를 보고 권한 문제로 결론 — 프로파일을 잘못 골랐을 가능성이 먼저다. 다른 후보를 확인한다
  • 프로브를 매번 전 프로파일에 돌림 — 캐시에 빈칸인 것만 던진다
  • 쓰기를 "확인차" 실행 — dry-run 옵션이 있어도 실행하지 않는다. 명령어만 낸다
  • 자동 선택했으면서 어떤 프로파일을 썼는지 말하지 않음 — 결과의 신뢰도가 프로파일에 달려 있으므로 항상 명시한다
  • 계정이 다른 프로파일을 맥락만 보고 자동 선택