AWSネットワーク構成図の手動更新が辛い?よろしい、ならばCloudMapperだ

株式会社ビズリーチで、SREエンジニアとして勤務しているmassです。2017年4月に入社してから、HRMOSというサービスのAWSのインフラを管理したり、アーキテクチャの設計・構築をしたりしています。

今回は、入社してから半年経ったらいつのまにかサービスのネットワーク管理者になっていて、そこで発生した問題と、それを解決するのに非常に役立ったCloudMapperというOSSを紹介したいと思います。

発生した問題

私がネットワーク管理者を引き継いだ段階では、ネットワーク構成図が作成されておらず、以下の問題が発生していました。

  • ロードバランサーを止められない
    • 用途不明のロードバランサーが存在したため、停止を検討した。
    • しかし、どのリソースから利用されているか見えず、不用意に停止できなかった。
  • 用途不明なEC2インスタンスの調査ができない
    • AWSからメンテナンス通知が来た対象が用途不明なEC2インスタンスだった。
    • 停止を判断するためsshでインスタンスに入ろうとしたが、インスタンスへのssh経路を把握できず調査が難しかった。

理論上はすべてのAWSリソースがコード管理されていれば、コードをもとにネットワーク構成図を作成することができます。
しかし、HRMOSのインフラの中でも古いAWSリソースはコード管理されておらず、必要な情報を確認するにはAWSのコンソールにログインして一つ一つ情報を集める必要がありました。

ネットワーク構成図をどう作成しようとしたか

大前提として、手動でやったら負けと考えました。

手動での更新作業はミスや更新漏れが起きやすく、実際に使える有用な構成図を提供できないと考えたためです。

特に、オンプレミスの場合はネットワーク構成をそれほど頻繁に変更しないので、手動でネットワーク構成図を作成するのが普通でしたが、 クラウドの場合はオンプレとは比較にならないほど短いスパンで構成変更していくので、それをすべて手動で反映していくのは現実的ではないと考えました。

その為、自動で更新されるネットワーク構成図の作成という方向で進めることにしました。

そして、具体的な手段を探していた時に、CloudMapperというOSSを見つけたのです。

CloudMapperとは

CloudMapperとは、2018/02に公開されたOSSで、READMEに記載された文章を日本語に大まかに訳すと以下の機能があると書いてあります。

  • AWSの環境を解析して、ネットワーク構成図を生成するよ!
  • ブラウザで表示できるよ!
  • AWSのリソースを視覚化するのに役出つよ!

これを使えばネットワーク構成図の自動作成・更新が可能にになると考えました。

実際に出来上がったサンプル見ると、非常に綺麗なネットワーク図ができていました。素晴らしい!
また、ブラウザ上の操作で、選択したインスタンス(以下画像では”Web2”インスタンス)について、設定値や繋がっているインスタンスに関する情報も参照できます。(以下画像右側のウィンドウ)

CloudMapperOfficial 生成されたネットワーク構成図のサンプル画像

運用自動化に向けて行ったこと

実運用にあたって、ネットワーク構成図の作成と更新に加え、CloudMapper自体のバージョンアップ反映もすべて自動化することにしました。

  • ネットワーク構成図の更新
    • CloudMapperは起動時に最新の情報を取得して構成図を更新するため、毎朝7時に再起動するようにした
    • 再起動処理は、CloudWatch Events -> Lambda で実装
  • CloudMapperのバージョンアップや設定変更の反映
    • OfficialDockerfileentrypoint.shを適時変更して、これらのファイルをGitHubのリポジトリで管理
    • ECS上でServiceとして稼働させた。ECSに関するAWSのリソースはTerraformでコード化しGitHubのリポジトリで管理
    • CodePipelineを利用し、GitHubのmasterにコミットがあったら、Docker Imageをbuildし、ECSのServiceにdeployを行うように設定

これにより、ネットワーク構成図が毎日最新化されるのに加え、CloudMapperのバージョンアップや、情報取得対象のAWSのアカウント追加があった場合も、設定ファイルをコミットするだけで自動反映されるようになりました。

セキュリティとコスト上の工夫

nginxによるアクセス制御

CloudMapperへのアクセスは社内のみに制限していましたが、それだけでは社内の誰でも参照できてしまうのでアクセス制限をかける必要がありました。

CloudMapper自体にはユーザー管理や権限制御の機能はなかったため、CloudMapperとALBの間にnginxを挟み、Basic認証を入れるようにしました。

AWSアカウントごとの制御と、コスト節約の為のECS Service化

担当しているサービスでは複数のAWSアカウント(本番、検証など)を管理しており、これらすべてのアカウントでCloudMapperを利用するにあたり、閲覧制限をアカウント単位でかける必要がありました。
このため、アカウント別にCloudMapperを構築することで、アカウント単位での閲覧制限をかけられるようにしました。

しかし、アカウントの数だけECSのServiceを構築すると金銭的なコストもかかるため、Serviceとしては一つ、Task側でアカウント単位のコンテナを構築しました。
また、一つのServiceで複数のCloudMapperにリクエストを分散させるため、nginxのproxyを利用しました。

register-task-definition.jsonの中身を抜粋

  {
    "name": "sandbox", #sandboxサービス
    "image": "xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/cloudmapper:latest",
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group": "/aws/ecs/task/cloudmapper",
        "awslogs-region": "ap-northeast-1"
      }
    },
    "memory": 512,
    "portMappings": [
      {
        "hostPort": 8010,
        "containerPort": 8000,
        "protocol": "tcp"
      }
    ],
    "environment": [
      {
        "name": "ACCOUNT",
        "value": "sandbox"
      },
      {
        "name": "AWS_DEFAULT_REGION",
        "value": "ap-northeast-1"
      },
      {
        "name": "AWS_REGION",
        "value": "ap-northeast-1"
      }
    ],
    "essential": true
  },
  {
    "name": "sandbox-us", #sandbox-usサービス
    "image": "xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/cloudmapper:latest",
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group": "/aws/ecs/task/cloudmapper",
        "awslogs-region": "ap-northeast-1"
      }
    },
    "memory": 512,
    "portMappings": [
      {
        "hostPort": 8020,
        "containerPort": 8000,
        "protocol": "tcp"
      }
    ],
    "environment": [
      {
        "name": "ACCOUNT",
        "value": "sandbox-us"
      },
      {
        "name": "AWS_DEFAULT_REGION",
        "value": "us-east-1"
      },
      {
        "name": "AWS_REGION",
        "value": "us-east-1"
      }
    ],
    "essential": true
  },
  {
    "name": "cloudmapper-nginx-proxy",
    "image": "xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/cloudmapper-nginx-proxy:latest",
    "links": ["sandbox", "sandbox-us"],
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group": "/aws/ecs/task/cloudmapper-nginx-proxy",
        "awslogs-region": "ap-northeast-1"
      }
    },
    "memory": 256,
    "portMappings": [
      {
        "hostPort": 0,
        "containerPort": 80,
        "protocol": "tcp"
      }
    ],
    "environment": [
      {
        "name": "SANDBOX",
        "value": "sandbox:8000"
      },
      {
        "name": "SANDBOX_US",
        "value": "sandbox-us:8000"
      }
    ],
    "essential": true
  }

nginxのproxy設定を抜粋

location /sandbox {
  # for sandbox
  auth_basic           "Welcome to sandbox";
  auth_basic_user_file /etc/nginx/.htpasswd;
  proxy_set_header        Host ${DOLLAR}host;
  proxy_set_header        X-Real-IP ${DOLLAR}remote_addr;
  proxy_set_header        X-Forwarded-For ${DOLLAR}proxy_add_x_forwarded_for;
  proxy_set_header        X-Forwarded-Proto ${DOLLAR}scheme;
  proxy_set_header        X-Forwarded-Host ${DOLLAR}http_host;
  proxy_pass http://${SANDBOX}/;
}

導入結果

ネットワーク構成の可視化によりわかったこと

常に最新のネットワーク構成図を提供できるようになったことで、ネットワークの全体像や個別リソースの役割と関係性が簡単に把握できるようになり、以下のようなことがわかりました。

  • 放置されていた、これまで知らなかったサーバの存在や、すでに不要となったELBやProxyなどの存在
  • 特定のEC2インスタンスを調査したい際、どのような経路にアクセスできるか
  • 思った以上にネットワーク設計が複雑になっていたこと

可視化された複雑さ

おそらく図をご覧いただければ一目瞭然ですね・・・。 (こちらはSREチームのメンテナンス用のインスタンスなのでセキュリティ的に公開して問題ないものになります)

CloudMapperSample

第一印象を端的にまとめると、なんか汚い ですよね。

しかし、それはCloudMapperが悪いのではありません、実際に複雑な設定になっているものがそのまま図示されているのです。今回の図で特にグレーの線が多いのは、変更作業の影響を局所化するために、個別のサービス単位でSecurityGroupを作成しており、それが全て描画されているためです。

これは予想外の気づきでしたが、CloudMapperのおかげで、今後のSecurityGroupの作成ポリシーを変更するきっかけになりました。

まとめ

ネットワーク設定の部分は手を加える機会が少ないので、塩漬け状態で管理するケースも少なくないです。しかし、ここ数年はインフラレイヤーも変化が激しく、放置しておくとあっという間にレガシーな環境になってしまうため、日々更新されていきます。今携わっているシステムも、3年ほど前に作られたシステムですが、1年ごとに大きくネットワーク構成が変わっていたことがわかりました。

今回の課題に取り組んだことで、インフラのコード化(Infrastructure as Code)だけではシステムの全体像の把握は難しく、さらに手動でのドキュメント更新は現実的ではないことがわかりました。 それに対して、CloudMapperやいくつかの仕組みを組み合わせることで、AWSのリソース可視化を自動で手軽にできることがわかりました。

今後の展望

昨今といっても数年前からですが、CloudNativeComputingFoundationという団体が設立されたように、CloudNativeと呼ばれるクラウドを前提としたシステム設計が浸透しはじめています。

CloudNativeになっても、リソース管理とは完全に無縁ではいられません。逆に、急速にサービス・リソースが拡大・縮小する時代だからこそ、運用作業もそれに追随するようなスピードが求められます。しかし、旧来の運用作業で変化に追随していくのは非常に厳しいのが現実です。

このため、運用作業の徹底した効率化、もっというと No Ops!の方向に向かうべきだと考えています。

今回のようなネットワーク構成図の作成も、構成が頻繁に変わるからこそ自動化が重要なファクターになりました。システム構成の変更に合わせて運用作業を柔軟に変更していくためにも、情報の可視化、手動作業の削減を日々行っていく必要があります。

今後も運用作業を無くし、No Ops!の方向に突き進んでいきたいと思います。