access key 없이 로컬 AWS 로그인: aws login과 브라우저 컨테이너

들어가며

로컬에서 AWS를 다루다 보면 가장 먼저 하는 일이 access key 발급입니다. ~/.aws/credentialsaws_access_key_idaws_secret_access_key를 넣거나, 조금 더 신경 쓰면 1Password 같은 곳에 넣어 두고 셸에서 주입하는 식입니다.

그런데 이 장기 키(long-term key)는 만들어 두는 것 자체가 부담입니다. 파일에 평문으로 남고, 로그나 히스토리, 프로세스 환경변수로 새어 나갈 창구가 많고, 회전(rotation)도 사람이 챙겨야 합니다. 1Password로 감춰 둔다 해도 결국 어느 순간엔 프로세스 환경으로 풀려 나옵니다.

그래서 방향을 하나 잡았습니다. 장기 키를 로컬에 아예 만들지 않는다. 이번 글은 그 목표를 AWS CLI에 이미 들어 있는 aws login과 mise 훅, 그리고 브라우저 컨테이너로 풀어낸 과정을 정리한 것입니다.

1. 문제 정의: 노출될 창구 자체를 없애고 싶다

처음 든 생각은 "1Password에 넣으면 되지 않나"였습니다. 실제로 많이 쓰는 방식이고, 파일에 평문으로 두는 것보다는 확실히 낫습니다. op run이나 플러그인으로 실행 시점에만 주입하면 디스크에는 안 남습니다.

하지만 한 발 더 들어가 보면 아쉬운 지점이 남습니다.

그래서 목표를 이렇게 다시 적었습니다. "값을 잘 숨기는" 게 아니라, 로컬에 장기 키를 만들지 않고, 노출될 값 자체를 짧은 수명의 임시 자격증명으로 바꾼다. 노출돼도 몇 시간이면 만료되고, 애초에 파일로 남지 않는 형태가 이상적입니다.

장기 키 vs 임시 자격증명

장기 access key는 사람이 지우기 전까지 유효합니다. 반면 STS 임시 자격증명은 세션 만료 시각이 정해져 있어, 새어 나가도 수명이 짧습니다. IAM의 권장 방향도 "장기 키를 만들지 말고 임시 자격증명을 쓰라"입니다.

2. aws login — 공식 CLI에 이미 있었다

서드파티 도구(aws-vault 등)를 찾아보던 중, AWS CLI v2에 login 명령이 그냥 들어 있다는 걸 알게 됐습니다. 별도 설치가 필요 없는 내장 명령입니다.

$ aws login help
LOGIN()

NAME
       login -

DESCRIPTION
       Login for local development using AWS Management Console credentials.
       Each time the login command is called, the CLI will acquire temporary
       credentials and a refresh token that correspond to your selected
       console session. ...

핵심은 **"AWS 관리 콘솔 세션의 자격증명으로 로컬 개발용 임시 자격증명을 받는다"**는 것입니다. 동작을 풀어 보면 이렇습니다.

프로파일 설정도 단순합니다. ~/.aws/config에 로그인 대상만 지정해 두면 됩니다.

[profile dr-dev]
login_session = arn:aws:iam::123456789012:user/your.name

이제 로그인은 프로파일을 지정해 부르기만 하면 됩니다.

aws login --profile dr-dev

한 번 로그인해 두면 이후 aws s3 ls --profile dr-dev 같은 명령이 임시 자격증명으로 돌아가고, 만료가 다가오면 리프레시 토큰으로 알아서 갱신됩니다. aws_access_key_id를 직접 만질 일이 사라집니다.

3. mise enter 훅으로 세션 자동 갱신

문제는 "매번 로그인 명령을 챙겨 부르는" 번거로움입니다. 세션이 만료됐는지 신경 쓰기도 싫었습니다. 그래서 프로젝트에 들어갈 때 유효한 세션이 없을 때만 자동으로 로그인하도록 mise 훅에 걸었습니다.

.mise.toml은 이렇게 정리됐습니다.

[settings]
# enter 훅은 이 mise 버전에서 실험 기능이라 활성화 필요(이 프로젝트에만 스코프).
experimental = true

[env]
AWS_DEFAULT_REGION = "ap-northeast-2"
AWS_REGION = "ap-northeast-2"

# 디렉터리 진입 시: 유효 세션이 없을 때만 자동 로그인(있으면 조용히 통과).
[hooks]
enter = "aws sts get-caller-identity --profile dr-dev >/dev/null 2>&1 || aws login --profile dr-dev"

[tasks.aws-login]
description = "AWS 임시 로그인/갱신 (aws login, 액세스 키 없이 12h 세션)"
run = "aws login --profile dr-dev"

동작의 요지는 enter 훅 한 줄입니다.

aws sts get-caller-identity --profile dr-dev >/dev/null 2>&1 || aws login --profile dr-dev

get-caller-identity로 세션이 살아 있는지 먼저 확인하고, 성공하면 아무 일도 안 일어나며 조용히 통과합니다. 실패(만료/미로그인)했을 때만 aws login이 뜹니다. 디렉터리에 들어갈 때마다 매번 로그인을 강요하지 않으면서, 필요한 순간에만 자동으로 갱신되는 셈입니다.

이전에는 이 자리에 access key를 주입하는 _.source 스크립트가 있었는데, 그걸 통째로 걷어냈습니다. 로컬 개발에서 장기 키를 참조하는 경로가 사라진 것이 이번 전환의 핵심입니다.

전환 후엔 실제 권한으로 확인

자격증명 방식만 바꾼 것이라 권한이 이전과 동일하게 붙는지 확인해 두면 마음이 놓입니다. aws sts get-caller-identity로 신원을 보고, 실제로 쓰는 서비스(EC2/IAM/Route53/S3/ECR/SSM 등)에 read 호출을 한 번씩 던져 보고, 마지막으로 tofu plan(또는 terraform plan)을 끝까지 돌려 상태 백엔드 접근까지 확인하면 end-to-end로 검증됩니다.

4. 브라우저 컨테이너로 프로젝트별 세션 분리

여기서 aws login의 성격이 뜻밖의 이점으로 이어졌습니다. 이 명령은 브라우저의 콘솔 세션을 기반으로 자격증명을 받아 옵니다. 그렇다면 브라우저에서 로그인 세션을 여러 개로 나눠 두면, 그 각각을 별도의 CLI 프로파일로 이어 붙일 수 있습니다.

여기서 유용한 게 브라우저의 컨테이너입니다.

개인 프로젝트, 외주 프로젝트, 회사 계정처럼 로그인 주체가 다른 콘솔 세션을 컨테이너별로 따로 유지해 두면 이렇게 굴러갑니다.

각 컨테이너의 콘솔 세션이 각 프로파일의 임시 자격증명 소스가 됩니다. 계정이 섞일 걱정 없이, 프로젝트마다 별개 프로파일을 깔끔하게 운용할 수 있습니다. 장기 키를 계정 수만큼 발급해 관리하던 것에 비하면 훨씬 마음이 편합니다. 브라우저에서 이미 세션을 나눠 쓰고 있었다면, 그 구분이 그대로 CLI 프로파일 구분으로 이어지는 셈입니다.

마치며

이번 전환의 핵심은 하나입니다. 로컬에 장기 access key를 만들지 않는 것.

1Password로 잘 숨기는 것도 방법이지만, 숨기는 것과 아예 없애는 것은 다릅니다. AWS CLI에 이미 들어 있는 aws login은 콘솔 세션 기반의 짧은 수명 임시 자격증명을 주고, mise enter 훅은 그걸 필요한 순간에만 자동으로 갱신해 줍니다. 여기에 브라우저 컨테이너로 프로젝트별 콘솔 세션을 나눠 두면, 프로파일 분리까지 자연스럽게 따라옵니다.

노출될 값 자체를 짧은 수명으로 바꾸고, 참조 경로를 없애고, 계정별 세션을 브라우저에서 이미 나눠 쓰던 방식 그대로 CLI로 잇는다 — 이 세 가지가 맞물리니, 로컬 AWS 자격증명을 두고 신경 쓰던 일이 눈에 띄게 줄었습니다.

감사합니다.