<p align="center">
<img src="https://raw.githubusercontent.com/TocConsulting/awsmap/HEAD/assets/logo.png" alt="awsmap" width="160" style="height: auto;"></p>
<p align="center">
<a href="https://pypi.org/project/awsmap/"><img src="https://img.shields.io/pypi/v/awsmap.svg" alt="PyPI version"></a>
<a href="https://pepy.tech/project/awsmap"><img src="https://static.pepy.tech/badge/awsmap" alt="Downloads"></a>
<a href="https://hub.docker.com/r/tarekcheikh/awsmap"><img src="https://img.shields.io/docker/v/tarekcheikh/awsmap?label=docker" alt="Docker"></a>
<a href="https://hub.docker.com/r/tarekcheikh/awsmap"><img src="https://img.shields.io/docker/pulls/tarekcheikh/awsmap" alt="Docker Pulls"></a>
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-brightgreen.svg" alt="License: MIT"></a>
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.11+-blue.svg" alt="Python 3.11+"></a>
<a href="https://aws.amazon.com/"><img src="https://img.shields.io/badge/AWS-150%2B_Services-orange.svg" alt="AWS Services"></a>
</p>
awsmap
150개 이상의 서비스와 모든 리전을 아우르는 AWS 리소스를 매핑하고 인벤토리화하는 빠르고 포괄적인 도구입니다.
<p align="center">
<img src="https://raw.githubusercontent.com/TocConsulting/awsmap/HEAD/assets/demo.gif" alt="awsmap demo: scan, SQL query, security queries, and natural-language ask" width="100%"></p>
주요 기능
- 150개 이상의 AWS 서비스 지원: 컴퓨팅(compute), 스토리지(storage), 데이터베이스(database), 네트워킹(networking), 보안(security) 등 다양한 영역을 포괄합니다.
- 다중 리전(Multi-Region): 활성화된 모든 리전을 병렬로 스캔합니다.
- 로컬 데이터베이스: 모든 스캔 기록이 SQLite에 자동 저장되어 오프라인으로 인벤토리를 쿼리할 수 있습니다.
- SQL 쿼리 엔진: 인벤토리 기록에 대해 SQL을 실행합니다 (
awsmap query "SELECT ...").
- 사전 구축된 쿼리 라이브러리: 사용 준비가 된 보안 및 규정 준수(compliance) 쿼리 30가지가 제공됩니다 (
awsmap query -n admin-users).
- 자연어 쿼리: 일반 영어로 질문할 수 있습니다. 의존성이 없고 별도의 설정 없이 바로 작동합니다 (
awsmap ask show me all EC2 without Owner tag).
- 예제 라이브러리: 서비스별로 정리된 실행 가능한 질문 1,381가지가 준비되어 있습니다 (
awsmap examples lambda).
- 다중 계정(Multi-Account): 여러 AWS 계정을 스캔하고 모든 계정에 걸쳐 쿼리할 수 있습니다.
- 태그 필터링: 태그별로 필터링합니다. 동일한 태그의 여러 값은 'ANY'에 해당하며 (Owner=John OR Jane), 다른 태그는 'ALL'에 해당합니다 (Owner=John AND Environment=Production).
- 아름다운 HTML 보고서: 검색, 필터, 다크 모드 및 내보내기 기능이 포함된 인터랙티브 보고서를 제공합니다.
- 다양한 출력 형식: JSON, CSV, HTML 형식을 지원합니다.
- 속도(Fast): 40개의 워커를 사용한 병렬 실행이 가능하며 (일반적인 계정의 경우 약 2분 소요), 속도가 빠릅니다.
- 드리프트 감지(Drift Detection): 시간 경과에 따른 스냅샷을 비교하여 추가되거나 제거되거나 수정된 리소스를 감지합니다 (
awsmap diff).
- 낭비 감지(Waste Detection): 수집된 데이터에서 유휴 또는 비효율적인 리소스를 찾으며 추가 API 호출이 필요 없습니다 (
awsmap waste).
- 태그 규정 준수(Tag Compliance): 필요한 태그 대비 태깅 커버리지를 감사하고 점수를 매깁니다 (
awsmap tags).
- 스캔 범위 쿼리(Scan-Scoped Queries): 현재 상태뿐만 아니라 스캔 기록의 모든 시점의 데이터를 쿼리할 수 있습니다 (
awsmap query --scan, awsmap ask --scan).
- 콘솔 로그인 지원:
aws login 자격 증명 제공자와 함께 작동합니다.
설치(Installation)
PyPI
필수 조건: Python 3.11 이상, AWS 자격 증명이 설정되어 있어야 합니다.
Docker
docker pull tarekcheikh/awsmap
또는 로컬에서 빌드합니다:
git clone https://github.com/TocConsulting/awsmap.git
cd awsmap
docker build -t awsmap .
개발 설치(Development Installation)
git clone https://github.com/TocConsulting/awsmap.git
cd awsmap
pip install -e .
Docker 사용법(Docker Usage)
docker run --rm \
-v ~/.aws:/root/.aws:ro \
...
사용법(Usage)
다중 계정(Multi-Account)
여러 개의 AWS 계정을 스캔합니다. 각 스캔은 동일한 로컬 데이터베이스에 저장되며, 이 데이터베이스를 통해 모든 데이터를 쿼리할 수 있습니다.
awsmap -p production
awsmap -p staging
...
AWS Organizations (다중 계정 병렬 스캔)
전체 AWS Organization 또는 Organizational Unit (OU)을 높은 처리량과 내장된 최소 권한(Least Privilege) 보안으로 병렬 스캔하고 인벤토리화합니다.
awsmap org -p org-root
...
전체 계정은 약 2,300개의 (서비스, 리전) 작업으로 구성되며, 각 작업당 약 2.7개의 API 호출이 필요합니다. 실제 103개 계정을 가진 조직에서 측정했을 때, 제한 사항은 CPU나 AWS 스로틀링(throttling)이 아닙니다. 바로 새로운 TLS 연결입니다 (호출당 하나씩 열 경우 초당 약 50회로 제한되지만, 재사용되는 keep-alive 연결의 경우 동일한 스레드로 약 440회/초에 도달합니다). awsmap org는 연결 재사용을 중심으로 구축되었습니다:
- 작업 단위(Work units): 계정은 배치 단위로 처리됩니다 (
-c, --concurrency, 기본값 4 × 프로세스, 최소 8). 최대 8개 계정에 걸친 동일한 (서비스, 리전) 작업들은 하나의 단위가 되어, 단일 스레드와 단일 keep-alive HTTPS 연결을 통해 실행됩니다. 각 요청은 처리 중인 계정을 위해 서명(signed)되며, 다른 컨텍스트의 호출은 다른 ID를 사용하려 하기보다 실패합니다.
- 유한 소켓(Bounded sockets): 단위가 작업을 마치면 클라이언트를 닫기 때문에 열린 연결은 스레드 수에 가깝게 유지됩니다.
- 공유 큐(One shared queue): 몇 개의 워커 프로세스(
-j, --processes, 기본값은 코어당 하나, 최대 6)를 위한 단일 공유 큐를 사용합니다. 서비스나 리전이 느린 경우 해당 스레드가 실행을 담당하며, 이전 배치가 처리되는 동안 다음 배치를 전송(dispatch)합니다.
- 동시성(Concurrency,
-w, --workers): 모든 워커에 걸친 총 동시 작업 단위 수입니다 (기본값: 256).
- 호출당 낮은 CPU 사용량: 각 워커는 서비스 모델을 한 번만 파싱하고 CA 번들(CA bundle)을 한 번만 로드합니다 (TLS 연결당 한 번씩 로드하는 방식 대비).
- 스로틀링으로 인한 데이터 손실 없음: 모든 API 응답이 검사됩니다. 스로틀링에 걸리거나, 5xx 오류가 발생하거나, 타임아웃된 작업은 재시도(최대 2회)되며, 요약 보고서는 여전히 미완료인 항목을 보고합니다. 어떤 계정에서도 도달할 수 없는 엔드포인트(해당 리전에서 제공되지 않는 서비스)는 감지되어 건너뜁니다.
- 불필요한 호출 없음: botocore의 엔드포인트 데이터에 따라 존재하지 않는 (서비스, 리전) 쌍은 건너뛰고, 멤버 계정 옵트인(member-account opt-in) 리전을 존중하며, IAM / S3 / Lambda별 리소스 호출은 병렬화됩니다 (제한적).
- 데이터베이스 경합 없음(Zero Database Contention): 스레드 안전 큐(thread-safe queue)에서 데이터를 소비하는 전용 SQLite 쓰기 스레드를 사용합니다. 수집기는 SQLite 잠금 문제로 인해 절대 블록되거나 오류를 발생시키지 않습니다.
최소 권한 IAM 세션 정책 (Least-Privilege IAM Session Policy)
OrganizationAccountAccessRole과 같은 표준 관리자 역할을 가정(assuming)할 때에도, awsmap org는 sts:AssumeRole에 전달되는 인라인 IAM 세션 정책을 동적으로 생성합니다. AWS IAM 평가 논리에 따라:
- 엄격한 읽기 전용(Strictly Read-Only): 메타데이터 검사 API(
*:Describe*, *:List*, *:Get*)만 허용하도록 권한이 교차됩니다.
- 민감 데이터에 대한 명시적 거부(Explicit Deny on Sensitive Data): 객체 페이로드, 비밀 값, 파라미터 또는 데이터베이스 테이블을 읽는 행위(
s3:GetObject*, secretsmanager:GetSecretValue, ssm:GetParameter*, kms:Decrypt, dynamodb:GetItem, dynamodb:Scan 등)를 명시적으로 차단합니다.
- STS 준수(STS Compliant): 2,048자 제한을 충족하도록 최소화된 JSON이 보장됩니다.
전체 역할 권한이 명시적으로 필요한 경우 --no-session-policy로 비활성화할 수 있습니다.
인벤토리 조회 (Query Your Inventory)
모든 스캔은 로컬 SQLite 데이터베이스(~/.awsmap/inventory.db)에 자동으로 저장됩니다. 원시 SQL 또는 자연 언어를 사용하여 오프라인으로 쿼리할 수 있습니다.
SQL 쿼리
awsmap query "SELECT service, COUNT(*) as count FROM resources GROUP BY service ORDER BY count DESC"
...
더 많은 SQL 예제: 사용자가 커스터마이징할 수 있는 준비된 쿼리 템플릿은 examples/queries/*.sql을 참조하십시오.
사전 구축된 쿼리 라이브러리
awsmap은 일반적인 보안, 규정 준수 및 운영 작업을 위한 30개의 사전 구축된 쿼리를 제공합니다. SQL 지식이 필요하지 않습니다.
매개변수 형식: parameter가 쿼리 매개변수 이름(tag, service 등)이고 value가 검색하려는 값인 경우 -P parameter=value를 사용하십시오. 예시: -P tag=Owner는 "Owner 태그로 필터링"을 의미합니다 (NOT -P Owner=SomeValue).
사용 가능한 쿼리:
| 쿼리 | 설명 | 예시 |
|---|
| IAM / 보안 | | |
| ... | | |
자체 쿼리를 추가하려면 .sql 파일을 ~/.awsmap/queries/에 배치하십시오. 내장된 쿼리와 동일한 헤더 형식(-- name:, -- description:, -- params:)을 사용하십시오. | | |
자연어 쿼리
awsmap ask를 사용하여 평이한 영어로 인벤토리에 대한 질문을 하십시오. 설정이 필요 없습니다 - 내장된 제로 의존성 파서와 함께 바로 작동합니다.
awsmap ask how many resources per region
awsmap ask show me all EC2 instances without Owner tag
awsmap ask which S3 buckets are in eu-west-1
...
awsmap은 사용자의 질문을 내장 파서(제로 의존성)를 사용하여 SQL로 번역하고, 생성된 쿼리를 보여주며, 결과를 표시합니다.
예제 라이브러리
awsmap examples를 사용하여 AWS 서비스별로 정리된 1381개의 사전 구축 질문을 찾아 실행하십시오.
다중 계정 쿼리
여러 계정이 스캔된 경우, awsmap ask는 기본적으로 모든 계정을 쿼리합니다. 단일 계정으로 범위를 제한하려면 -a를 사용하십시오:
awsmap ask show me all IAM users
...
드리프트 감지 (Drift Detection)
시간이 지남에 따라 AWS 인벤토리 스냅샷을 비교하여 변경된 사항(추가, 제거 또는 수정된 리소스)을 감지합니다.
작동 방식: awsmap은 스캔 기록에서 시점별(point-in-time) 스냅샷을 재구성합니다. 각 (계정, 서비스)에 대해 주어진 날짜보다 같거나 빠른 최신 스캔을 찾아 두 스냅샷을 필드별로 비교합니다. 이는 부분 스캔도 정확하게 처리합니다. 예를 들어, 월요일에 EC2를 스캔하고 화요일에 S3를 스캔했다면, 각 서비스는 자체적인 최신 스캔을 사용합니다.
--from이 없는 경우, awsmap diff는 가장 최근 스캔 이전의 상태와 현재 상태를 비교하여, 최신 스캔에서 정확히 무엇이 변경되었는지 확인할 수 있습니다. --from 없이 --to만 지정하면, --from은 --to 바로 직전의 스캔으로 기본 설정됩니다.
상대 날짜: 7d, 30d, 90d, yesterday, today, 또는 2026-01-15와 같은 정확한 날짜를 사용할 수 있습니다.
변경 유형:
- Added (추가됨) - 리소스가 더 새로운 스냅샷에는 존재하지만 이전 스냅샷에는 존재하지 않는 경우
- Removed (제거됨) - 리소스가 이전 스냅샷에는 존재하지만 더 새로운 스냅샷에는 존재하지 않는 경우
- Modified (수정됨) - 리소스가 둘 다에 존재하지만 세부 정보, 태그 또는 이름이 변경된 경우 (필드별 비교 포함)
자원 낭비 감지 (Waste Detection)
awsmap이 이미 수집한 데이터를 기반으로 유휴 상태이거나 잠재적으로 낭비되는 리소스를 찾습니다. 새로운 AWS API 호출은 없으며, 규칙들은 가장 최근에 저장된 스냅샷을 대상으로 실행됩니다.
규칙:
| Rule key | What it flags |
|---|
unattached-ebs | EBS 볼륨이 available 상태인 경우 |
| ... | |
awsmap은 카운트와 조치를 취할 리소스를 보고합니다. 달러 비용을 추정하지는 않습니다. 출력 형식은 table(기본값), json, 또는 html입니다. --include-defaults를 전달하지 않는 한, is_default 리소스는 제외됩니다. | |
태그 준수 (Tag Compliance)
인벤토리 전반의 태깅 커버리지를 감사하고, 필수 태그 세트에 따라 점수를 매깁니다. 이미 수집된 데이터를 기반으로 작동합니다.
이 보고서는 전체 준수 점수, 필수 태그별 커버리지(어떤 태그가 누락되었는지 확인할 수 있음), 서비스별 세부 내역, 그리고 누락된 태그와 함께 비준수 리스트를 보여줍니다.
- 필수 태그는
-R/--required (쉼표로 구분 또는 반복 가능)에서 가져오거나 required_tags 설정 키를 사용합니다. 둘 다 지정되지 않은 경우, 준수는 "최소한 하나의 태그가 있음"으로 기본값이 적용됩니다.
- 빈 태그 값(예:
Owner=)은 누락된 것으로 간주됩니다.
is_default 리소스는 기본적으로 제외되며, 포함하려면 --include-defaults를 전달하십시오.
- 기본 필수 세트를 한 번 설정합니다:
awsmap config set required_tags Owner,Environment,CostCenter.
- 출력 형식은
table(기본값), json, 또는 html입니다.
특정 스캔 조회 (Querying a Specific Scan)
기본적으로 query와 ask는 현재 스냅샷(is_current)을 대상으로 실행됩니다. --scan을 사용하여 기록된 모든 스캔을 대상으로 지정할 수 있습니다.
awsmap query --list-scans
...