BIGLOBEの「はたらく人」と「トガッた技術」

AWSマネコン操作時のうっかり事故を防止する為のChrome拡張作ってみた

AWSをマネージメントコンソールから操作する時、つい「うっかり」”開発”環境のつもりで”本番”環境を触ってしまったりした事はないですか? 今回はそんなミスを防ぐ為のChrome拡張を作ってみました。

こんにちは、プロダクト技術本部の松田です。

今回は趣味プログラミングとして作ったGoogle Chrome拡張をご紹介します。

AWSをマネージメントコンソールから操作する時、つい「うっかり」”開発”環境のつもりで”本番”環境を触ったりした事はないですか?

今回はそんなミスを防ぐ為の Chrome拡張 を作ってみた話を紹介します。

作った人の属性ですが

  • インフラよりのエンジニア

  • 普段から仕事でAWSには頻繁にふれている

  • 好きなAWSサービスはLambda

  • よく使う言語はPython、Bash

  • JavaScriptの知識は 2000年頭頃の知識で止まってる

  (かろうじて Ajaxを使ったGoogleマップとかGoogleスプレッドシートに感動した記憶がある)

といった感じです。

今回作ったもの

今回作ったのは、こちらの AWS Safety Switch Role です。

chromewebstore.google.com

Chrome Web StoreからChromeに追加後、AWSマネコン画面上で拡張アイコンをクリックするとPopup画面が表示されます。

Popup画面から Configration ボタンを押すと、オプションページが表示されます。

初期状態では、デフォルトの色設定(AWSのマネコンで設定出来るのと同じ内容)のみ設定されています。

Profile追加を押してSwitch Role設定を登録します。

登録画面が出るので、Switch Role設定を投入し「変更を適用」ボタンを押し登録します。

登録すると一覧にSwitch Role設定が表示されます。

再び、AWSマネコン画面を表示、拡張アイコンをクリックすると、先ほど登録した内容が表示されます。

また “表示中のアカウントをMenuに取り込む” ボタンを押すと、現在表示している AWSアカウント・Roleの組み合わせを 登録してくれます。

ダークモード表示 設定で登録した サービスA をクリックしてみます。

無事サービスAにSwitch Roleし、画面もダークモードで表示されました。

開発のきっかけ

AWSでの開発・運用では、サービス(製品)毎にAWSアカウントを分離し、作業の区分毎にRoleを分ける運用を行う事が多いです。

例えば、製品Aと製品Bではそれぞれ、別のAWSアカウントを用いて、アカウントレベルで製品Aと製品Bを分離します。

その上で、製品Aと製品Bの間でデータ交換などが必要な場合、S3などのストレージを使った共有や、APIやPeeringでのNW接続などを用いて必要なデータや機能の呼び出しを行う形が多いかと思います。

製品Aを操作する場合でも、

  • 環境を構築するインフラエンジニア

  • プログラムのデプロイやログ調査を行うデベロッパー

  • 環境維持やアラームの管理を行う運用オペレータ

などで操作する対象リソースや必要な権限は変わってきます。 これらは、それぞれ固有のRoleを使って、そのRoleにSwitch Roleして作業する事が多いかと思います。

また同じ製品Aでも、本番環境だけではなく、開発環境、評価環境など用途に応じて環境毎にAWSアカウントを分離してプログラムやデータ、ネットワークを分離することが多いです。

この様に、1つの担当サービスであっても複数のAWSアカウントを切り替えて操作する事があり、また一人の人が複数の役割を兼任する(例えばデベロッパーだが運用も行うなど)事も多いので、実際の業務では様々な AWSアカウントやRoleを切り替えながら作業する事になります。

さらに、複数の製品の開発担当者になったり、複数の製品を横断して担当する運用者やインフラ担当者もあり、個人で扱うAWSアカウント・Roleの組み合わせが多岐にわたる事はよくあります。

ここで発生するのが

  • 「開発環境」のつもりで「本番環境」を触っちゃった

  • 思っていたものとは違う製品のリソースを消しちゃった

などの、うっかり作業ミスです。

作業用のAWSアカウント・Roleによっては本番環境を破壊できる危険なものも多いのですが、AWSマネジメントコンソールでは、操作しているAWSアカウント・Roleは危険性の高いものか?低いものか?が視覚的に判らないので「うっかりミス」を招くケースが多いと思っていました。

そこで少しでも「うっかりミス」を減らせるような物を作りたいと思い今回のChrome拡張を作成しました。

実現してみたい機能

  • AWSマネコンの標準機能では、5つしかSwitch Role設定を記憶できない。これを大幅に増やしたい。

  • 大量のSwitch Role設定からSwitch先を検索でサクッ見つけて素早く切り替えたい。

  • 大量のSwitch Role設定をラベルなどを使ってある程度グルーピングが出来るようにしたい。

  • AWSマネコン操作時に危険性が高い環境(本番環境での高権限など)は、視覚的に判るようにしたい。例えば、本番環境ではDarkモード表示、管理者アカウントではヘッダーフッターが赤くなる等を自由に設定したい。

  • 拡張機能の設定(Switch Roleのリストや色設定など)は、ファイルとしてExportして他の人と共有できるようにしたい。またプログラムなどで自動生成出来るような構造にしておきたい。

  • 誰でも簡単に利用開始出来るようにしたい。(なのでChrome拡張を採用)

実際にChrome拡張を作ってみた

前置き

このChrome拡張は日曜プログラマーとして個人作成しているので、色々手を抜いている箇所が多いのですが大目に見ていただけると幸いです。

設計書を書いてないとか、テストプログラムを書いてないとか、コードが汚いとか、それはもう色々と。。

また細かい制作内容を書くと長くなりそうなので、主にどういった流れや思考プロセスで制作したか?に絞って書こうと思います。

Chrome拡張作成については、Googleの Chrome for Developers に詳しく記載されています。

developer.chrome.com

全体構成を考えてみる

まず初めに大体どんな作りになるかをイメージしてみました。

Chromeでアドレスバーの横に拡張機能のアイコンが表示される。

拡張機能のアイコンをクリックするとSwitch Role一覧がPopup表示される。

拡張機能アイコンをクリックするとSwitch Role一覧がPopup表示される。
拡張機能アイコンをクリックするとSwitch Role一覧がPopup表示される。

拡張機能のオプション画面で、Switch Role設定を登録する。

また登録した内容を、テキストファイルとしてExport / Importできる。

拡張機能のオプション画面で、Switch Role設定を登録
拡張機能のオプション画面で、Switch Role設定を登録

その他としては、AWSマネコンの標準機能からSwitch Roleした場合でも、指定した色設定などは有効になる。

まぁざっくりとこんな感じで考えました。

Chrome拡張としての構成を考えてみる

次に実装にあたって、Chrome拡張としてどんな構成になるのか?を考えてみました。

全体構成から考えると

a.コンテンツスクリプト

表示されているページのDOM操作などが出来るJavaScript

実装する機能は概ね次の通り

  • 現在ページのAWSアカウントやロールの組み合わせを取得して予め指定した色やDarkモードなどを設定する。

  • Popupページからのメッセージを受け指定されたAWSアカウント・RoleにSwitch Roleする。

b.ツールバーアクション

ツールバーの拡張機能アイコンをクリックした時に表示するHTMLページ(Popupページ)

実装する機能は概ね次の通り

  • オプション画面で登録されたSwitch Roleリスト(AWSアカウントとRoleの組合せリスト)を表示する。

  • Switch Roleリストがクリックされた場合、表示中のコンテンツスクリプトに、Switch先の情報を送信する。

  • 検索フィルタ内容に応じ動的にSwitch Roleリストを組み立てる。

c.オプションページ

拡張機能の設定メニューから呼び出せる設定ページ

実装する機能は概ね次の通り

  • Switch Roleのリストを登録する。

  • 登録内容のInport/Exportを行う。

この辺りを実装して拡張機能としてマニフェストファイルを構成すれば良さそうでファイル構造は概ねこんな感じにしようと思います。

<root>
|--manifest.json            <manifestファイル>
|--option.html          <optionページ HTML>
|--popup.html           <popupメニュー HTML>
|
|--css              HTMLで利用するStyleSheet群
|  |--option.css
|  |--popup.css
|
|--js
|  |--content.js            <contentスクリプト>
|  |--option.js         <optionページのスクリプト>
|  |--popup.js          <popupメニューのスクリプト>

細かい部分は作りながら考える方向で進めました。

作ってみる

作ってみるとは書きましたが、実際にJavaScriptのコードの記述などは、素人の自分よりずっと良い記事がネット上に色々あるので特に記載しません。

今回は、実装する時にどうやって実装しようかと困った点や、AWSマネジメントコンソールの内容を調べた時の事について書いてみます。

!!注意!!

今回のChrome拡張を作るにあたり、AWSマネジメントコンソールの内容を独自に調査し仕組みの一部を利用しています。

今回記載している内容は、2023年10月時点でのもので、今後AWS様のアップデートによって随時変更になる可能性があります。

制作に入る前に、まずは機能の根幹であるSwitch Roleする部分がAWSマネコン上でどのように行われているかを調べてみました。

手始めにAWSマネジメントコンソールで ロールの切り替え ボタンを押すと出てくるページから解析してみます。

ロールの切り替え
ロールの切り替え

このページの ロール切り替え ボタンが押された時の挙動を調べてみます。

HTMLのソースを見てみると幾つかのhiddenパラメータをつけて自身(https://signin.aws.amazon.com/switchrole)を呼び出している様です。

developer.chrome.com

記述されている場所は、HTML(https://signin.aws.amazon.com/switchrole)の下記部分の周辺です。

<form id="switchrole_form" name="switchrole_form" action="/switchrole" method="POST">

付与しているパラメータは

  Switch先のAWSのAccountID

  Switch先のRole名

  カラーコード

  表示名

  呼び出し元URL

  csrfフィールドに入った数値

辺りになります(その他は固定値でも大丈夫そう)

csrfフィールドですが、CSRF(Cross Site Request Forgery)対策用トークンを入れているようです。 記述されている場所は、HTML(https://signin.aws.amazon.com/switchrole)の下記部分の周辺です。(実際は改行とかはなかったりします)

var calculateChecksum=function(c){
         var a=1,b=0;
         if(!c){
               return 0;
         }
         for(var i=0;i<c.length;++i){
                 a=(a+c.charCodeAt(i))%65521;
                 b=(b+a)%65521;
         }
         return(b<<15)|a;
};

〜(略)〜

var xsrf=calculateChecksum(getCookie("aws-userInfo"));

Switch Roleのページ(https://signin.aws.amazon.com/switchrole)では未定義なのですが、AWSマネコンの各ページでは AWSCというオブジェクトが存在しています。

特に公開情報が有るわけではないのですが、マネコンのログイン情報などが格納されているオブジェクトで、例えばコンソールホームなどで呼び出されているPHD(Personal Health Dashboard)を表示する際にログインされているか?などの判定に使われているようです。(https://phd.aws.amazon.com/phd/auth)

AWSCのオブジェクトは https://a.b.cdn.console.awsstatic.com/〜略〜/awsc-head.js あたりで定義されているようです。

このAWSCオブジェクトのgetMbtcというメソッドを使って同様の値を取得することが出来そうです。

実際に計算している箇所は、awsc-head.js の下記コード周辺にあります。

const qn = {
            getMbtc: ()=>jn,
~(略)~
initPlatformAuth: e=>{
Fn = e.location,
           jn = (e=>{
            let a = 1
                  , o = 0;
                if (!e)
                        return 0;
                for (let t = 0; t < e.length; ++t)
                        a = (a + e.charCodeAt(t)) % 65521,
                        o = (o + a) % 65521;
                return o << 15 | a
            }

変数名は違えど同じ計算式なので大丈夫そうです。

実際に AWSC.Auth.getMbtc() で取得した値を詰めてSubmitした所、ちゃんとSwitch Role出来たので利用できそうです。

というわけで、Popupメニューから指定されたAWSアカウント・RoleにSwitchするときは、AWSC.Auth.getMbtc() で取得した値を詰めてhttps://signin.aws.amazon.com/switchrole を呼び出す事にします。

次にAWSマネコンの背景色を変更する方法を検討しました。

AWSマネコンでは、見た目を変更する機能として Darkモード、Lightモードを指定する事ができます。

これはHTMLのソースコードを見ればすぐ判るのですが bodyの class で制御しています。

   ダークモード

    <body spellcheck="false" class="awsui-polaris-dark-mode">

   ライトモード

    <body spellcheck="false" class="">

これだけですと2種類の色分けしか出来ないので、全体的に背景色をいじってみたい所です。

結論から言うと、自身が JavaScript/CSSが苦手ということもあり十分な解析はできませんでした。

(恐らくフレームワークなどである程度可変に名前つけされる???などで、細かい箇所の指定が難しそう)

ひとまず

 ヘッダー部分のクラスが .globalNav-{何かの数値}

 フッター部分のクラスが ._awsc-footer

である事は判ったので、こいつの背景色を設定することにします。

実際に設定してみた所、それっぽい感じに表示されるようになったので暫定で良しとしました。

その他の実装

AWSCオブジェクトへのアクセスですが、Content Scriptからは直接アクセスができません。

なので、

  • Content Scriptで事前に DOM操作で受け渡し用のFormを作成

  • Content Scriptで動的にAWSC情報取得用JavaScriptをAWSマネコンにアタッチ

  • AWSC情報取得用ScriptでAWSC情報を取得して受け渡しFormに詰める

といった方式で回避しています。

その他にも色々とコーディングはしたのですが、特別な苦労というより単に知識不足により時間がかかっただけなので省略します。

実際に拡張機能を動かしてみる

Chrome拡張として動作させる為には、拡張機能としての振る舞いを指定するマニフェストの作成が必要になります。

また自作したChrome拡張を試すには、Chromeの拡張機能のデベロッパーモードを有効化してから、パッケージ化されていない拡張機能を読み込む 必要があります。

まずはマニフェストを作成します。

マニフェストの書き方はChrome for Developer に詳しく記載されています。

developer.chrome.com

インターネット上で調べる場合 manifest_version に注意してください。

(現在は利用できないV2の情報が多いです)

今回は指定した主要な内容は次の通りです

  • permissions

  利用したChromeの機能を列挙

  今回は tab, strage, unlimitedStrage, downloads を指定

  • content_scripts

    js/content.js と動作させるURL(https://.aws.amazon.com/)

  • web_accessible_resources

  ユーザScriptと同じレイヤで動作させるScript

  今回の場合、AWSCオブジェクトのアクセス用のScriptを指定

  • action

    Iconクリック時のPopupメニューページを指定(popup.html)

  * options_page

  Chrome拡張の設定ページを指定(option.html)

を指定しました。

次に実際にChromeに拡張機能として登録し動かしてみます。

Chromeで自作の拡張機能を登録するにはデベロッパーモードを有効化してから パッケージ化されていない拡張機能を読み込む で登録する必要があります。

後は実際に拡張機能アイコンをクリックして動作を確認してください。

デバッグ時に各ページのデバッグをどうするかちょっと困ったのでその辺りも共有しておきます。

  • Contentスクリプト

マネコンページを表示後、Chromeのデベロッパーツールで動作確認

  • Popupメニュー

拡張機能アイコンをクリックする事でポップアップメニューを表示 表示したポップアップメニュー上で CTRL+右クリック => 検証 で専用のデベロッパーコンソールを表示

  • オプションページ

オプションページを表示後、デベロッパーツールで動作確認

Chrome Web Storeに公開してみる

作成した拡張機能を、誰でも簡単に使えるようにする為には、Chrome Web Store への登録が必要です。

chromewebstore.google.com

Chrome Web Store への登録の為にはChrome ウェブストアのデベロッパー登録が必要で、未登録の状態で遷移すると登録ページが表示されます。

デベロッパー登録には、$5 USDかかります。

デベロッパー登録を行う事で、デベロッパーページにアクセス出来るようになります。

デベロッパーページにアクセス出来るようになったら、最初にデベロッパーとしての情報を登録します。

デベロッパー情報は、拡張機能の公開ページで公開される情報になるので気をつけて登録してください。

何となく登録しちゃうと、場合によっては、個人のメールアドレスや自宅の住所を ”全世界公開”しちゃう事になります。

デベロッパーダッシュボードの左ペインから「アカウント」を選択し、アカウントページを呼び出します。

アカウントページでは以下の情報を登録します。

  • 投稿者の表示名:

 Web Storeの提供元として表示されます。

  • 連絡先メールアドレス: 

 Web Storeでデベロッパーのメールアドレスとして公開されます。

 個人アドレスをそのまま使うのは避けた方が良さそうです。

  • トレーダーの申告:

 EU向けに商売(AD含む何らかの手段で収益化)する予定がない場合、非取引業者アカウントで良いと思います。

  • 住所:

 登録しちゃうとChrome Web Storeで公開されてしまうので、個人の場合は登録しない方が安心できます。

  • 管理:

 特定のユーザやグループのみに機能を提供したい場合、Trusted Testerアカウントに登録します。

ようやく拡張機能を公開する準備が整ったので、実際に公開してみます。

まずは作ったChrome拡張をZIP圧縮します。

デベロッパーコンソールで、左ペイン「アイテム」=> 「新しいアイテム」をクリックします。

表示されたアイテム追加ダイアログに、ZIP圧縮したChrome拡張をドロップします。

ドロップするとChrome拡張ファイルがアップロードされて、ストア掲載情報の登録が始まります。

まずは「ストアの掲載情報」の情報登録からはじめます。

最低限以下の項目を登録する必要があります。

  • 説明

  拡張機能の紹介や利用時のメリットを記載します。

  Chrome Web Store のアイテム紹介ページで 概要として表示されます。

chromewebstore.google.com

  • カテゴリ

  拡張機能が格納されるカテゴリを選択します。

  今回は ツール を選択

  • 言語

  主な対応言語を選択

  マルチランゲージで構成したら出てこないかも知れませんが、自分は日本語のみで作ったので日本語を設定しました。

  • ショップアイコン

 Chrome Web Store のアイテム紹介ページで表示されるアイコン。

  • スクリーンショット

 Chrome Web Store のアイテム紹介ページで表示されるスクリーンショット画像、最低1枚は必要です。

  サイズ:1280x800 または 640x400

  JPEG または PNG(24bit)

これら情報の他にオプションで プロモーション動画(YouTubeのURL)や公式ページのURL、サポートページのURLなどを追加する事ができます。

またGoogleアナリティクスの有効化をすることもでき、有効化した場合、利用状況などを閲覧する事ができます。

次に「プライバシー」の情報登録を行います。

以下の項目を登録する必要があります。

  • 単一用途の説明

  このChrome拡張の簡潔な説明を記載します。

  恐らく審査時のみ使われる内容となります。

  • 権限が必要な理由

  マニフェストのPermissionで指定した各種権限が必要な理由を記載します。

  今回は

    tab => Popupメニューから操作中の tabを判定する。

    strage => アプリのconfigを保存する。

    unlimitedstrage => configサイズが大きい為。

    downloads => configをexportする。

    ホスト権限(content scriptの利用)=> AWSマネコン画面を操作する。

  この様な感じで説明しました。

  • リモートコードの有無

  パッケージ外からCSSやSscriptを取り込む場合は、説明の必要があります。

  今回はありません。

  • ユーザデータの収集の有無

  何らかのユーザデータを収集するChrome拡張の場合、収集内容を説明する必要があります。

  また、収集する場合、プライバシーポリシーのURLを記載する必要があります。

  今回はありません。

  • プライバシーポリシーURL

    プライバシーポリシーの掲載URL

  今回はありません。

最後に「販売地域」の情報を登録します。

販売・地域情報

  有料・無料

  公開設定

  販売地域(ストア掲載地域)

を設定します

全ての情報の登録が終わったら「審査のため送信」ボタンから審査リクエストを行うと、Google側で審査が行われます。

経験的に概ね3日前後で審査が終わる事が多いです。

権限の審査は結構厳しめで、マニフェストファイルのPermissionに利用していない権限を書いていると高確率で弾かれます。 最小限のPermissionを記載するようにしてください。

最後に

今回は、AWSを少しでも、

 「快適」「安全」

に利用できるよう(そして個人的な知的探究心を満足させる為に)作った Chrome拡張の製造・公開の過程などを紹介しました。

普段はあまり気にする事の無いAWSマネコン画面の裏側(実装)を覗いてみたり、 Chrome拡張を一般公開して見たりと少しマニアックな内容になってしまいました。

記事内には記載しきれませんでしたが、ちゃんとしたChrome拡張を作って気づけたことも山ほどあり個人的にはなかなか楽しめたと思っています。

苦手意識を持っていた為、普段あまり触れることのないJavaScriptでしたが、これを機会にもう少しだけ勉強してみようと思えた事は収穫でした。

まだまだ機能や完成度に物足りない部分も色々とありますが、これからも少しずつ手を入れてゆくつもりなので温かい目で見守ってください。

※ Amazon Web Services、AWS、AWSのロゴは、米国その他の諸国における、Amazon.com, Inc. またはその関連会社の商標です。

※ Google、Google Chrome、Chrome、YouTubeは、Google LLCの商標です。本BlogはGoogleによって承認されたり、Google と提携したりするものではありません。

※ Java、JavaScriptは、Oracle、その子会社及び関連会社の米国及びその他の国における登録商標です。

※ その他、記載している団体、製品名、サービス名称は各社またはその関連会社の商標または登録商標です。