CloudMapperをDockerで動かして、AWSのネットワーク構成を可視化しよう。


こんにちは。

AWSいいですよね。
でも、AWSって一つ一つのサービスがしっかり役割分担されているので、いざ一つのシステムとしてネットワーク構成図がどうなっているのかをみようとすると頭がこんがらがっちゃうんです、私。

そんなときCloudMapperにお世話になりたくなります。READMEを読んでいただければですが、現在のAWSのネットワーク構成図を自動生成してくれるやつです。
ただ、何度かチャレンジしているのですが、いつも何かが足りなくてうまく動かないんです、私。最近は何をやるにもDockerでやっちゃっているのでローカル環境もあんまり汚したくなくて...

CloudMapper公式や他の方々もDockerで動くようにソースコードを公開していたりするんですが、なんでかうまく行かなかったりしたので、今回は自分でDockerfileから作ってみようという記事です。

前提

  • AWSアカウントがあること
  • SecurityAuditViewOnlyAccessの権限をもったIAM(以下、IAM_A)があること(よくわからなければ最悪AdministratorAccessの権限でもひとまずOK)
  • IAM_AのアクセスキーIDとシークレットアクセスキーを払い出していること
  • DockerおよびDocker Composeが利用可能であること

CloudMapperが動くDockerイメージを作る

CloudMapperはPythonで動いているのでPythonのDockerイメージをベースに必要なパッケージをインストールしたDockerイメージを作るためのDockerfileを作成します。

Dockerfile
FROM python:latest

RUN git clone https://github.com/duo-labs/cloudmapper.git && \
    pip install \
      jinja2 \
      netaddr \
      parliament \
      policyuniverse \
      pyjq \ 
      pyyaml && \
    apt update -qq && \
    apt install -q -y vim

最初にgitCloudMapperのソースコードをダウンロードしています。

PythonのDockerイメージを使うと、READMEで必要と言われているパッケージはほとんど入っているようで、実際にCloudMapperを実行しようとしたときに追加で必要になったパッケージをpipコマンドで追加してあげています。

vimはコンテナ内でファイルを編集したい時などに使いたいのでインストール。

次にDocker Compose用のファイルを作ります。

docker-compose.yml
version: "3"

services:
  cm:
    build: .
    working_dir: /cloudmapper
    ports:
      - 8000:8000
    environment:
      - AWS_ACCESS_KEY_ID=[IAM_AのアクセスキーID]
      - AWS_SECRET_ACCESS_KEY=[IAM_Aのシークレットアクセスキー]
    volumes:
      - ./config.json:/cloudmapper/config.json

working_dir

cloudmappergit cloneしているのでDockerイメージの中には/cloudmapperというディレクトリができています。そこをワーキングディレクトリにします。

ports

CloudMapperのViewを表示するポートです。8000がデフォルトなのでそれに合わせて。

environment

ここでIAM_AのアクセスキーIDとシークレットアクセスキーを環境変数に定義します。

volumes

この後書きますが、CloudMapperが情報を取得しにいくAWS AccountのAccount IDを設定するconfig.jsonが必要になるのでローカルのファイルをマウントするようにしています。コンテナの中で書き換えてもいいのですが、毎回書くのは面倒なのでローカルのファイルと同期しておきます。

config.jsonも作っておきましょう。CloudMapperのソースコードにあるconfig.json.demoを参考に以下のように書きます。

config.json
{ 
  "accounts": [
    {
      "id": "[AWSのAccount ID]",
      "name": "[識別名]",
      "default": true
    }
  ],
  "cidrs": {}
}

AWSのAccount IDはコンソールの「マイアカウント」から確認できます。(12桁の数字。もしどこ見ればいいの?って方はこの記事の最後のAppendix2のやり方とかみてみてください。)

ここまで準備ができたらDockerイメージをビルドします。

$ docker-compose build

CloudMapperをDockerコンテナで動かす

ビルドが完了したらコンテナの中でCloudMapperを動かしてみましょう!

まずコンテナを起動させて中に入ります。

$ docker-compose run --service-ports cm bash

--service-portsオプションはdocker-compose runコマンドを実行するときにdocker-compose.ymlの中のportsを適用させるためのオプションです。これがないとローカル環境からhttp://localhost経由でCloudMapperのWebページにアクセスできないので注意です。

コンテナの中に入ったらAWSからデータを収集します。

# python cloudmapper.py collect

このコマンドでAWSアカウントのネットワーク構成情報をめっちゃ取得してくれます。
全てのリージョンの全ての情報を取ってきているみたいで結構時間がかかります。
毎回これをやるのはきついんで何回もコンテナを消して立ち上げ直してとやる場合は、/cloudmapper/account-data/をマウントしておけばこの工程を省けます。(このディレクトリにデータを生成している工程なので)

情報を取得できたらレポートを作成します。

# python cloudmapper.py prepare
# python cloudmapper.py report --accounts [IAM_Aの識別子]

最後に収集してレポートを作ったサイトを公開します。

# python cloudmapper.py webserver --public

さぁ!これでhttp://localhost:8000にアクセスしてみましょう!


こちらは公式のイメージですが、こんな感じのページが表示されるはずです!

まとめ

CloudMapperをDockerで動かすことができました!
READMEを見ると色々とパッケージのインストールなどが大変そうだな(実際つまづいた)という感じだったのですが、Dockerですっきりと動かせました〜。

Appendix1: CloudMapperのヘルプ

READMEだけだとあんまりわからなかったのですが、cloudmapper.pyはhelp機能がついてました。

# python cloudmapper.py -h

CloudMapper 2.8.2
usage: cloudmapper.py [access_check|amis|api_endpoints|audit|collect|configure|find_admins|find_unused|iam_report|prepare|public|report|sg_ips|stats|weboftrust|webserver] [...]
  access_check: [proof-of-concept] Check who has access to a resource
  amis: Cross-reference EC2 instances with AMI information
  api_endpoints: [Deprecated] Map API Gateway end-points
  audit: Identify potential issues such as public S3 buckets
  collect: Run AWS API calls to collect data from the account
  configure: Add and remove items from the config file
  find_admins: Find privileged users and roles in accounts
  find_unused: Find unused resources in accounts
  iam_report: Create IAM report
  prepare: Generate network connection information file
  public: Find publicly exposed services and their ports
  report: Create report
  sg_ips: Find all IPs are that are given trusted access via Security Groups
  stats: Print counts of resources for accounts
  weboftrust: Create Web Of Trust diagram for accounts
  webserver: Run a webserver to display network or web of trust map
# python cloudmapper.py collect -h

usage: cloudmapper.py [-h] [--config CONFIG] [--account ACCOUNT_NAME]
                      [--profile PROFILE_NAME] [--clean]
                      [--max-attempts MAX_ATTEMPTS]

optional arguments:
  -h, --help            show this help message and exit
  --config CONFIG       Config file name
  --account ACCOUNT_NAME
                        Account to collect from
  --profile PROFILE_NAME
                        AWS profile name
  --clean               Remove any existing data for the account before
                        gathering
  --max-attempts MAX_ATTEMPTS
                        Override Botocore config max_attempts (default 4)

チェックしてみると使い方が良くわかるかもしれないです!(webserver--publicオプションはこれで見つけられた...)

Appendix2: AWS Account IDを調べる

AWS Account IDはAWS CLIで取得することもできます。
この記事で作成したコンテナではAWS CLIを使えないのでDockerfileを少し更新します。

Dockerfile
  FROM python:latest

  RUN git clone https://github.com/duo-labs/cloudmapper.git && \
      pip install \
+       awscli \
        jinja2 \
        netaddr \
        parliament \
        policyuniverse \
        pyjq \ 
        pyyaml && \
      apt update -qq && \
      apt install -q -y vim

ビルドしてDockerコンテナの中で以下のコマンドを実行します。

# aws sts get-caller-identity
{
  "UserId": "XXXXXXXXXXXXXXXXXXXX",
  "Account": "123456789012",
  "Arn": "arn:aws:iam::123456789012:user/xxxxxxxxxx"
}

ここのAccountに表示されている数字列がAccount IDです。
参考:【小ネタ】AWS CLIでAWS Account IDが取れるようになりました! | Developers.IO