
歴史的経緯 (?) によって構成ドリフト状態(Infrastructure as Code 本参照)になっている Amazon EC2 インスタンスが複数台あって,まずはサーバーの期待値を宣言して自動テストもしくは自動検証をする仕組みを作りたいなぁーと考えていた💡
今までの経験としては,2014-2016年頃によく使っていて,過去にブログ記事を書いていたりもする Serverspec を思い出しつつ,Ruby に依存せず実行ファイルをポンッと置いたらすぐに使えるようなツールがあったら良いなぁーと思って探していたところ,Go で実装されていて,サーバーの期待値を YAML で宣言できる「Goss」を発見した👀 実際に試してみたらとても便利で最高だったので,検証ログをまとめて公開することにした❗️
検証環境
今回は別の検証環境として使っていた Amazon EC2 インスタンス (Amazon Linux 2023 AMI) を使う.
セットアップ
README を参考にセットアップする.現状だと v0.3.23 になった.
$ curl -fsSL https://goss.rocks/install | sh $ goss --version goss version v0.3.23
しかし README に Using curl | sh is not recommended for production systems と書いてあるため,本番環境などに使う場合はしっかりと VERSION を固定してインストールする👌 現時点で最新は v0.4.2 で,今回はこちらを使う.
$ VERSION=v0.4.2 $ curl -L "https://github.com/goss-org/goss/releases/download/${VERSION}/goss-linux-amd64" -o /usr/local/bin/goss $ chmod +rx /usr/local/bin/goss $ goss --version goss version v0.4.2
Goss でサポートしてるリソース
Goss では「サーバーの期待値を宣言できる」と書いたけど,実際には以下のように多くのリソースがサポートされている❗️
addr:google.com:80などリモートアドレスに疎通できるか検証するcommand:go versionなど任意のコマンドを実行した結果(標準出力・標準エラー・終了ステータスなど)を検証するdns:AレコードやCNAMEレコードなど名前解決の結果を検証するfile: ファイルやディレクトリの存在やowner/group/modeなどの設定を検証するgroup: Linux グループなどグループの設定を検証するhttp: HTTP リクエストを送信してレスポンス(ステータスコードなど)を検証するinterface:eth0などネットワークインタフェースの設定を検証するkernel-param:sysctlコマンドで設定できるカーネルパラメータを検証するmount: ファイルシステムのマウントポイントを検証するmatching: matcher 構文を使って任意の値を検証するpackage:httpdなどパッケージを検証するport:tcp:22などポートの状態を検証するprocess: プロセスの状態を検証するservice: サービスの状態を検証するuser: Linux ユーザーなどユーザーの設定を検証する
リソースの詳細やリソースごとの構文などは以下のドキュメント(マニュアル)に詳しくに載っている📝
Goss を試す
さっそく Goss を試していく❗️
🌷 サンプル: sshd
まずは README の Quick start に載っている sshd のサンプルを試す❗️
goss autoadd コマンドを使うと環境に最適な Goss ファイル goss.yaml を自動生成してくれる.
$ goss autoadd sshd
自動生成された goss.yaml は以下のようになっていた.自動的に port / service / user / group / process の検証項目が追加されていた👏
port: tcp:22: listening: true ip: - 0.0.0.0 tcp6:22: listening: true ip: - '::' service: sshd: enabled: true running: true user: sshd: exists: true uid: 74 gid: 74 groups: - sshd home: /usr/share/empty.sshd shell: /sbin/nologin group: sshd: exists: true gid: 74 process: sshd: running: true
Goss で検証を実行する場合は goss validate コマンドを実行する.今回は Failed: 0 となって「すべて成功」していた.
$ goss validate ............... Total Duration: 0.021s Count: 15, Failed: 0, Skipped: 0
期待通りの結果にならない状態にするため,意図的に sshd を止めて,もう一度 goss validate コマンドを実行すると,今度は Failed: 4 で「一部失敗」していた.
$ systemctl stop sshd $ goss validate FSFSF.........F Failures/Skipped: Port: tcp6:22: listening: Expected false to equal true Port: tcp6:22: ip: skipped Port: tcp:22: listening: Expected false to equal true Port: tcp:22: ip: skipped Process: sshd: running: Expected false to equal true Service: sshd: running: Expected false to equal true Total Duration: 0.022s Count: 15, Failed: 4, Skipped: 2
🌷 サンプル: amazon-ssm-agent
次は goss add コマンドを使って amazon-ssm-agent の Goss ファイルを生成する❗️
goss add コマンドは goss autoadd コマンドと違って package や service など具体的なリソースを指定して Goss ファイルを生成する.そして goss コマンドに --gossfile オプションを付けるとデフォルトの goss.yaml 以外のファイルを対象にできる.今回は amazon-ssm-agent の検証に限定するため,ファイル名を変えて Goss ファイル goss-ssm.yaml を生成する.
$ goss --gossfile goss-ssm.yaml add package amazon-ssm-agent $ goss --gossfile goss-ssm.yaml add service amazon-ssm-agent
自動生成された goss-ssm.yaml は以下のようになっていた.
package: amazon-ssm-agent: installed: true versions: - 3.2.1377.0-1.amzn2023 service: amazon-ssm-agent: enabled: true running: true
さらに file リソースも試したかったため,amazon-ssm-agent によって出力されるログファイル /var/log/amazon/ssm/amazon-ssm-agent.log も追加する.
$ goss --gossfile goss-ssm.yaml add file /var/log/amazon/ssm/amazon-ssm-agent.log
最終的に goss-ssm.yaml は以下のようになった.
file: /var/log/amazon/ssm/amazon-ssm-agent.log: exists: true mode: "0644" owner: root group: root filetype: file contents: [] package: amazon-ssm-agent: installed: true versions: - 3.2.1377.0-1.amzn2023 service: amazon-ssm-agent: enabled: true running: true
🌷 サンプル: openssl
今度は command リソースを試してみたく,openssl version コマンドを実行した結果(標準出力)の一致を検証する Goss ファイルを生成する❗️
$ goss --gossfile goss-openssl.yaml add command 'openssl version'
自動生成された goss-openssl.yaml は以下のようになっていた.
command: openssl version: exit-status: 0 stdout: - 'OpenSSL 3.0.8 7 Feb 2023 (Library: OpenSSL 3.0.8 7 Feb 2023)' stderr: "" timeout: 10000
🌷 サンプル: gossfile で Goss ファイルをまとめる
最初に生成した Goss ファイル goss.yaml を goss-sshd.yaml にリネームしてから,新しく以下の YAML で goss.yaml を作る.gossfile リソースでは指定した Goss ファイルをまとめることができるため,Goss ファイルを細かく分割しつつ,対象のサーバーに必要な検証項目をまとめて宣言できる.これは便利❗️
gossfile: goss-openssl.yaml: {} goss-sshd.yaml: {} goss-ssm.yaml: {}
現時点で Goss ファイルは4つある.
$ ls -1 goss-openssl.yaml goss-sshd.yaml goss-ssm.yaml goss.yaml
このまま goss validate コマンドを実行すると Count: 27 と表示されている通り,3つの Goss ファイルの検証項目をすべて実行できている \( 'ω')/ 良いじゃん〜
$ goss validate ........................... Total Duration: 0.086s Count: 27, Failed: 0, Skipped: 0
Goss エンドポイントを公開する
Goss で特徴的な(おもしろい)機能の一つとして goss serve コマンドがある.以下のように実行すると Goss の検証結果を取得できる API を起動できる❗️そして検証結果のフォーマットとしては json や junit や prometheus などを指定できるため,Goss の検証結果を他のサービスと連携できるようになっているのは拡張性がありそう \( 'ω')/
rspecish フォーマット API(デフォルト)
$ goss serve $ curl http://localhost:8080/healthz ........................... Total Duration: 0.077s Count: 27, Failed: 0, Skipped: 0
json フォーマット API
$ goss serve --format json $ curl -s http://localhost:8080/healthz | jq .summary { "failed-count": 0, "skipped-count": 0, "summary-line": "Count: 27, Failed: 0, Skipped: 0, Duration: 0.080s", "test-count": 27, "total-duration": 79993971 }
まとめ
サーバーの期待値を YAML で宣言して自動検証できる「Goss」を試してみた❗️最高〜 \( 'ω')/
現時点で Goss はリモート実行には対応してなく,検証するサーバーに Goss をセットアップして実行する必要があるため,AWS Systems Manager Run Command を使って Goss を実行する仕組みを検証しているところ.また別の記事にまとめようと思う📝