Python と WatchGuard Fireware CLI を使用してファイアウォール ルールの作成する
前回の Secplicity の記事では、WatchGuard Firebox Cloud の AWS への展開を自動化する方法を説明しました。関連する GitHub リポジトリに、WatchGuard Fireware CLI(Command Line Interface)を使用して Firebox を設定する Python コードがあります。このコードは、サーバをセットアップして構成することなくソースコードを実行する手段として、AWS Lambda 関数で実行されるものです。最近は、このようなコード実行で「サーバレス」が注目されており、これについては、Martin Fowler によるこの記事で詳しく説明されています。
前回の例では、サーバレスアーキテクチャを使用した AWS における Firebox の構成方法を紹介しましたが、AWS 以外の環境で同じことを行うのであれば、AWS や Lambda は必要ありません。正しいバージョンの Python と関連ライブラリをサポートしている任意のオペレーティングシステムで、Python コードを実行できます。サンプルコードでは、Paramiko ライブラリを使用して Firebox への SSH 接続を作成し、Boto3 ライブラリを使用して AWS コマンドを実行しています。AWS の外部でコードを実行する場合は、boto ライブラリを削除し、コードを変更して内部ファイルストレージに接続することで、他の場所にある Firebox に接続するための SSH キーを取得します。
このコードよりも少し複雑にはなりますが、共通する関数を別のファイルやクラスにわけて、他のプログラムでコードを再利用できるようにすることもできます。fireboxcommands.py をご覧ください。これは、Firebox の構成を実行するいくつかのコマンドを含む Python クラスです。Python や類似するプログラミング言語をご存知ない場合は、プログラミングの基礎を初めに理解されると良いかもしれません。プログラミングに関する知識をお持ちの方は、以下に示す、Python を使った Firebox Cloud の構成方法へとお進みください。
__init__ 関数に注目してください。プログラムがこのクラスを最初に使用する(ソフトウェアの専門用語で言うところの、そのクラステンプレートに基づいてオブジェクトを「インスタンス化する」)と、Python がこの初期化関数を実行して、Firebox への接続が作成されます。コード内の後続の関数は、この接続を使用して Firebox CLI にコマンドを送信します。
Firebox に接続するための SSH キーが必要であるため、このコードは、AWS S3 バケットに接続して、Firebox CLI 接続のための SSH キーを取得します。
AWS 以外の環境で実行する場合は、コードを変更して、ローカルのキーが置かれている場所からキーを取得します。local_key_file 変数で指定されている場所と名前にキーをダウンロードします。後続のコードは、この変数を使用して Firebox に接続します。
キーを保護する必要がありますが、その 1 つとして、ネットワークルールとシステム権限によって一部のマシンとアカウントだけにアクセスを制限したサーバのファイル共有にキーを置く方法が考えられます。キーをダウンロードするマシンと、キーの取得と Firebox のアクセスに使用するネットワークを保護します。
このコードでキーが取得されると、Firebox に接続してコマンドを実行できるようになります。Firebox コマンドは、クラス内のこれ以外の関数で実行されます。汎用的な関数では、送られてきたコマンドを実行し、さらには、コマンドが完了するのを待機し、発生する可能性があるいくつかのエラーも処理します。
専門的な処理を実行する関数では、コマンド文字列を作成し、必要な場合に(あるいは特定の順序で)コマンドをコールし、関連するエラー処理も実行します。たとえば、add_alias 関数は、Firebox エイリアスを作成し、エイリアスがすでに存在すると、delete 関数をコールします。次に、通常であれば Firebox への接続後にネットワーク管理者が端末ウィンドウに入力することになるエイリアスコマンド文字列を生成します。そして、そのコマンドを exe 関数に送信することで、そのコマンドが Firebox に送信されます。アスタリスク付きの FQDN エイリアスの場合、CLI は FQDN を一重引用符で囲む必要があるため、その点も処理で考慮します。
コマンドを実行するには、Firebox CLI が正しいモードである必要があり、モードが正しくないと、コマンドは失敗します。コマンドの正しいモードを調べるには、そのコマンドに対応するページの CLI ドキュメントのヘッダを探します。CLI でエラーが発生した場合は、CLI が正しいモードであることを確認してください。
あるモードでコマンドが完了したら、apply コマンドで Firebox に変更を適用してから、exit コマンドでそのモードを抜けます。この例の fireboxcommands.py クラスには、異なるモードを入ったり、変更を適用したり、モードを終了したりするためのメソッドがあります。
どのようなソフトウェアプログラムにおいても、不要になった接続をすべて終了することが重要です。接続を開いたままにすると、ネットワークが遅延し、セキュリティの問題やメモリリークが発生する可能性があります。close_connections 関数は、Firebox CLI への接続の終了を処理します。
このフォルダには、fireboxcommands.py クラスを使用して WatchGuard Firebox Cloud を設定する複数の Lambda 関数が含まれています。fireboxcommands.py クラスの使用方法については、fireboxcofig.py をクリックして確認してください。
このコードは最初に、変数の値を設定します。そして、AWS Lambda 環境変数から変数値を取得します。変数値の取得をハードコーディングすることも、AWS 以外であれば、選択した構成ファイルから変数を取得することもできます。
コードは次に、fireboxcommands クラスをインスタンス化します。上記の初期化関数には、AWS S3 バケットの名前が必要であり、これによって、キー、キーの名前、および Firebox の IP アドレスを取得できます。このコードを AWS 以外で実行する場合は、その環境に合わせて必要な箇所を変更してください。
fireboxcommands オブジェクトが正しく初期化されれば、Firebox への接続が確立されます。これで、他の関数で Firebox を構成できるようになりました。コードは最初に、必要なルールとエイリアスの存在チェックを実行します。現段階では、CLI を使用してルールとエイリアスを更新する方法はありません。ルールが存在していて、更新が必要な場合にルールを削除して追加し直すことができることを、ライブラリが知っておく必要があります。
次に、正しいモードに移行して Firebox を構成するためのコマンドを実行します。
最後に、開いている接続を閉じる関数をコールします。忘れてはならない重要事項として、必ず、finally を使用して接続を閉じるようにします。接続を閉じるコマンドが他のコマンドの末尾だけに存在する場合、エラー発生時にプログラムが停止して、接続を閉じるコマンドが実行されません。close_connections のコールが finally ブロックで発生すれば、前述の例外の場合であっても常に実行されます。
このコードはデモ目的であるため、経験豊富な Python プログラマから見れば、改良や機能拡張の余地が多くあるでしょう。ただし、ソースコードリポジトリに保存されているコードを出発点として使用することで、構成を自動化する方法を学べるはずです。この例によって、どのような環境においてもネットワーク管理者が自動化を使用し、セキュリティを強化できることをご理解いただければ幸いです。
— Teri Radichel(@teriradichel)