Macでgit-cryptとGPGを導入する時の覚え書き

Gitリポジトリを作ってgit-cryptのセットアップをする際、手順を忘れがちなのでメモに残しておく。

git-cryptとは

git-cryptというのは、Gitリポジトリ内のファイルを暗号化する為のGitプラグインであり、Gitのclean/smudgeフィルターを活用して、.gitattributesに指定したファイルをgit add時に暗号化、git checkout時には復号化といった具合で、透過的に暗号処理を施してくれるツール。

個人的に、Terraformを使ってインフラ構築する事がよくあるのだが、パスワード類や各種APIキー等の秘匿情報を、変数ファイル等にハードコーディングせざるを得ないケースがある為、そういったファイルをGit上で安全に管理するのに使っている。

git-cryptは暗号処理にAES-256のCTRモードが、認証と改竄検知にはHMAC-SHA1が使われており、これらの処理はOpenSSLに依存している。

また、暗号処理に使う対称鍵を安全に共有する手段として、GPGを利用出来る仕様にもなっている為、別途でGPGもインストールしておくと良い。

なお、類似ツールにgit-secretとか、暗号アルゴリズムを自分で選択可能にしたtranscryptというのもあるが、これらはWindowsをサポートしていない。

開発環境をMacLinuxに限定出来るのであれば、より強度の高い暗号アルゴリズムを設定出来るtranscryptを使う方が良いかと思う。

GPG(GNU Privacy Guard, GnuPG)とは

GPGについても軽く触れておくと、公開鍵暗号方式を利用して署名や暗号化したメールの送受信の実現を目的とする、Pretty Good Privacyの公開された標準仕様となるOpenPGPの実装であり、暗号鍵の生成とそれを使ったデータの暗号処理や署名、暗号通信を行うもの同士の公開鍵の束をローカルや公開鍵サーバーで共有&管理する為のツール群である。

コマンドラインで手軽に利用する事が出来て、一般的にはメールの暗号化であったり、Linux等の署名付きパッケージの真正性確認、Gitの署名付きコミットや、Zoomが買収したSNSのIDと暗号鍵を公にマッピングするKeybaseといったサービスで使ったりする。

git-cryptとGPGのインストール

Macの場合、git-cryptもGPGもHomebrewにパッケージがあるので、以下のコマンドを実行すればインストール出来る。

$ brew install git-crypt gnupg

対称鍵の共有にGPGを使わないのであれば、gnupg自体は不要なのだが、より安全な形での運用を目指すのであれば、インストールしておいた方が望ましい。

なお、おまけのツールとして、pinentry-macという、パスフレーズやPINコードをダイアログ入力形式で行える様にする為のツールであるpinentryMac拡張についても紹介しておく。

これを使うと、GPGの鍵に設定するパスフレーズの入力を、GUIのダイアログで行える様になるのだが、別に無くともCUIの画面全体がパスフレーズ入力画面に切り替わるので、必ずしも要る訳では無いものの、入力が分かり易くなるので、好みによって入れておくのも有りかと。

$ brew install pinentry-mac

インストールが完了したら、gpg-agentの設定ファイルとなる「~/.gnupg/gpg-agent.conf」に、pinentry-macを使用する為の下記設定を追記する。

$ echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf

これで準備はOK。

git-cryptの使い方

ここからは、git-cryptの利用方法について記載する。

まず、導入にあたり、git-cryptを利用したいGitリポジトリのルートディレクトリで、git-crypt initコマンドを実行する。

$ git-crypt init
Generating key...

すると、ローカルリポジトリである.gitディレクトリの中に、新たにgit-cryptディレクトリが作成され、ファイルの暗号処理に使う対称鍵が生成される。

.git/git-crypt/keys/default

また、.git/configファイルにはgit-crypt用のフィルターが追記され、これにより、透過的な暗号処理が実行される様になる。

[filter "git-crypt"]
    smudge = \"git-crypt\" smudge
    clean = \"git-crypt\" clean
    required = true
[diff "git-crypt"]
    textconv = \"git-crypt\" diff

暗号対象のファイルは.gitattributesを作成して、以下の様に指定してやれば良い。

*.txt filter=git-crypt diff=git-crypt

この場合だと、リポジトリ内に存在するtxt拡張子のファイルが全て暗号対象となる。

対称鍵の共有

git-cryptを個人利用するのであれば、ここまででOKなのだが、複数人で利用する場合となると、この暗号処理に使う対称鍵をメンバー間で共有する必要が出てくる。

そこで、まずはgit-cryptの導入者が、git-crypt export-keyコマンドを使用して、ローカルリポジトリにある対称鍵をファイルにエクスポートする。

$ git-crypt export-key ファイル名

このエクスポートした対称鍵を、何らかの安全な方法で共同作業するメンバーに受け渡す。

対称鍵を受け取ったメンバーは、git-cryptをインストールした後、暗号処理を施しているGitリポジトリをクローンして、リポジトリのルートディレクトリで以下のコマンドを実行する。

$ git-crypt unlock 対称鍵のファイルパス

すると、git-cryptは.git/git-crypt/keysディレクトリにこの対象鍵を配置し、.git/configにgit-cryptフィルターの設定を追記した上で、暗号化されているファイル群の復号処理を行う。

以後は各メンバーの環境でも、git-cryptによる透過的な暗号処理が行われる様になる。

この対称鍵の共有手段として、後述するGPGを利用する方法があり、セキュリティを考慮するのであればそちらが推奨されるのだが、CircleCIやGitHub Actions等でCI/CDを実施する場合等では、CI/CDの実行環境でGPGを使うのが手間だったりする為、対称鍵をBase64エンコードして環境変数に設定し、この方法を使っている。

GPGで安全に対称鍵を管理する

git-cryptの対称鍵をGPGを使ってより安全に共有する場合、まず、メンバー全員がgit-cryptに加えてgnupgのインストールも行い、gpgコマンドで公開鍵暗号方式のキーペアを作成する。

キーペアを作成する為のコマンドオプションは幾つかあるのだが、ここでは鍵の仕様を引数で指定する事が可能となっている--quick-generate-keyオプションを使う。

$ gpg --quick-generate-key "ユーザー名 <メールアドレス>" アルゴリズム 用途 有効期限

[実行例]
$ gpg --quick-generate-key "heroween <heroween@example.com>" default default 0

執筆時点のgnupgのバージョン2.3.7では、例示しているコマンドの様に第二引数と第三引数を「default」にすると、主鍵と副鍵それぞれのキーペアが作成され(第二引数が「default」以外の場合は主鍵のみ作成される)、アルゴリズムは主鍵が「ed25519」で副鍵が「cv25519」、用途は主鍵が「署名と証明」で副鍵が「暗号」となり、第四引数に「0」を指定しているので、各鍵の有効期限が無期限になる。

コマンドを実行したら、パスフレーズの入力画面に表示が切り替わるので、確認を含めて2回の入力を行うとキーペアの生成が完了(秘密鍵を使う際にはこのパスフレーズが必要となるので、忘れずに控えておく)。

gpg --list-keysコマンド(公開鍵の表示)やgpg --list-secret-keysコマンド(秘密鍵の表示)を実行すると、ローカルの鍵束に保存された鍵を確認する事が出来る。

$ gpg --list-keys
-------------------------------
pub   ed25519 2022-08-23 [SC]
      25ABCE8FFDC20D3FE5272C7B1B2A9FEAD1E71D4A
uid           [  究極  ] heroween <heroween@example.com>
sub   cv25519 2022-08-23 [E]

$ gpg --list-secret-keys
-------------------------------
sec   ed25519 2022-08-23 [SC]
      25ABCE8FFDC20D3FE5272C7B1B2A9FEAD1E71D4A
uid           [  究極  ] heroween <heroween@example.com>
ssb   cv25519 2022-08-23 [E]

メンバー各自の鍵が生成出来たら、以下のコマンドを実行してそれぞれの公開鍵をエクスポートしてもらい、その公開鍵をgit-cryptの導入者に受け渡す。

$ gpg -o ファイル名 --export 鍵ID

[実行例]
$ gpg -o heroween.public.gpg --export 25ABCE8FFDC20D3FE5272C7B1B2A9FEAD1E71D4A

指定する鍵IDについては、ユーザー名やメールアドレスでも代替が可能(上述の例だと、「heroween」や「heroween@example.com」となり、もしユーザー名にスペースが含まれる場合であればクォートで囲えばOK、以降の例示ではユーザー名を使用する)。

ちなみに、標準だと公開鍵はバイナリー形式でエクスポートされるが、--armorオプションを加えればASCII Armorでエクスポートする事も可能。

エクスポートされた公開鍵をメンバーから受け取ったgit-cryptの導入者は、それらをまず自身の鍵束にインポートする。

$ gpg --import ファイル名

[実行例]
$ gpg --import heroween.public.gpg
gpg: 鍵1B2A9FEAD1E71D4A: 公開鍵"heroween <heroween@example.com>"をインポートしました
gpg:           処理数の合計: 1
gpg:             インポート: 1

インポートした公開鍵は信用が「不明」になっている。

$ gpg --list-keys
-------------------------------
pub   ed25519 2022-08-23 [SC]
      25ABCE8FFDC20D3FE5272C7B1B2A9FEAD1E71D4A
uid           [  不明  ] heroween <heroween@example.com>
sub   cv25519 2022-08-23 [E]

gpg --edit-keyコマンドを使用すると、gpgのプロンプトが展開し、対話式に鍵の設定を変更する事が出来るので、trustコマンドで適切な信用を付与しておく。

$ gpg --edit-key 鍵ID

[実行例]
$ gpg --edit-key heroween
gpg (GnuPG) 2.3.7; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

pub  ed25519/1B2A9FEAD1E71D4A
     作成: 2022-08-23  有効期限: 無期限      利用法: SC
     信用: 不明の     有効性: 不明の
sub  cv25519/E625DB7981E23CFC
     作成: 2022-08-23  有効期限: 無期限      利用法: E
[  不明  ] (1). heroween <heroween@example.com>

gpg> trust
pub  ed25519/1B2A9FEAD1E71D4A
     作成: 2022-08-23  有効期限: 無期限      利用法: SC
     信用: 不明の     有効性: 不明の
sub  cv25519/E625DB7981E23CFC
     作成: 2022-08-23  有効期限: 無期限      利用法: E
[  不明  ] (1). heroween <heroween@example.com>

他のユーザの鍵を正しく検証するために、このユーザの信用度を決めてください
(パスポートを見せてもらったり、他から得たフィンガープリントを検査したり、などなど)

  1 = 知らない、または何とも言えない
  2 = 信用し ない
  3 = まぁまぁ信用する
  4 = 充分に信用する
  5 = 究極的に信用する
  m = メーン・メニューに戻る

あなたの決定は? 5
本当にこの鍵を究極的に信用しますか? (y/N) y

pub  ed25519/1B2A9FEAD1E71D4A
     作成: 2022-08-23  有効期限: 無期限      利用法: SC
     信用: 究極        有効性: 不明の
sub  cv25519/E625DB7981E23CFC
     作成: 2022-08-23  有効期限: 無期限      利用法: E
[  不明  ] (1). heroween <heroween@example.com>
プログラムを再起動するまで、表示された鍵の有効性は正しくないかもしれない、
ということを念頭においてください。

gpg> quit

上述の場合、自身で発行した公開鍵をエクスポートしておいて、一旦、削除してからインポートし直しているので、信用に「5 (究極)」を設定している。

再度、gpg --list-keysコマンドを実行すると、信頼が「不明」から「究極」に更新されている事が確認出来る。

$ gpg --list-keys                                                                                                                                                                           -------------------------------
pub   ed25519 2022-08-23 [SC]
      25ABCE8FFDC20D3FE5272C7B1B2A9FEAD1E71D4A
uid           [  究極  ] heroween <heroween@example.com>
sub   cv25519 2022-08-23 [E]

他人から受け取った公開鍵の場合は、適宜、署名の検証等を行って信頼を設定するが、その辺りの詳細は割愛。

こうして公開鍵をインポートし終えたら、git-cryptの導入者は、暗号処理対象のGitリポジトリをクローンし、リポジトリのルートディレクトリでgit-crypt initコマンドを実行する。

次に、インポートしたメンバー各自の公開鍵ID(自身のも含む)を、git-cryptにcollaboratorとして登録してやる。

$ git-crypt add-gpg-user 鍵ID

[実行例]
$ git-crypt add-gpg-user heroween
[main (root-commit) 7bd9435] Add 1 git-crypt collaborator
 2 files changed, 4 insertions(+)
 create mode 100644 .git-crypt/.gitattributes
 create mode 100644 .git-crypt/keys/default/0/25ABCE8FFDC20D3FE5272C7B1B2A9FEAD1E71D4A.gpg

すると、出力されるメッセージの通り、リポジトリ内に.git-cryptディレクトリが新規作成されて、配下に.gitattributes(初回のみ作成され、以後の編集は不可)と、登録したGPGの公開鍵を使って暗号化された対称鍵が配置される。

git-crypt add-gpg-userコマンドをメンバーの分だけ繰り返すと、.git-crypt/keys/default/0ディレクトリの配下には、メンバーそれぞれの公開鍵で暗号化された対称鍵が追加されていくので、それらの追加が完了したら、この.git-cryptディレクトリをリポジトリにコミットしてやる(.gitignore対称にしてはいけない)。

git-cryptの導入者によって.git-cryptディレクトリがコミットされたら、メンバーは各々の環境に対象のリポジトリをクローンし、以下のコマンドを実行する。

$ git-crypt unlock

コマンド実行したら、GPGの鍵を作成時に設定したパスフレーズを問われるので、そのパスフレーズを入力してやると、git-cryptがGPGの秘密鍵を使って対称鍵を復号して.git/git-crypt/keysディレクトリに配置し、.git/configにgit-cryptフィルターの設定を追記した上で、暗号化されているファイル群の復号処理を行い、以後は各メンバーの環境でも、git-cryptによる透過的な暗号処理が行われる様になる訳である。

git-cryptの対称鍵自体を暗号化してGitリポジトリ上で管理する形になるので、対称鍵を直に受け渡しするよりは安全で、かつ紛失する可能性も低くなる為、git-cryptを使用する場合は、基本的にこちらの方法が推奨される。

GPGのキーペアを共有する場合

クローズドな環境においては、メンバー間で個人に依存しない鍵を使い回す事もあるかと思うので、メンバー各自でGPGのキーペアを作成はせずに、git-cryptの導入者が作成したキーペアをメンバー間で共有する場合についても書いておく。

まずは、git-cryptの導入者が生成したGPGのキーペアをエクスポートするのだが、公開鍵のエクスポートについては既述している通り。

一方で、秘密鍵のエクスポートには、公開鍵のエクスポートとは異なる--export-secret-keysオプションを使う。

$ gpg -o ファイル名 --export-secret-keys 鍵ID

[実行例]
$ gpg -o heroween.private.gpg --export-secret-keys heroween

公開鍵の時とは異なり、秘密鍵のエクスポートコマンドを実行すると、キーペア作成時に設定したパスフレーズの入力を求められるので、控えていたパスフレーズを入力するとエクスポートが完了。

キーペアのエクスポートを完了したら、何らかの安全な方法でメンバーにキーペアを受け渡し、受け取ったメンバーはそのキーペアを自身のGPGの鍵束にインポートしてやる。

エクスポート時とは違って紛らわしいのだが、秘密鍵のインポートには公開鍵と同じ--importオプションを使う。

$ gpg --import ファイル名

[実行例]
 gpg --import heroween.private.gpg                                                                                                                                                         16:24:46
gpg: 鍵1B2A9FEAD1E71D4A:"heroween <heroween@example.com>"変更なし
gpg: warning: lower 3 bits of the secret key are not cleared
gpg: 鍵1B2A9FEAD1E71D4A: 秘密鍵をインポートしました
gpg:           処理数の合計: 1
gpg:               変更なし: 1
gpg:       秘密鍵の読み込み: 1
gpg:     秘密鍵のインポート: 1

これも、エクスポート時と同様に、コマンド実行をしたらパスフレーズを求められるので、メンバーはgit-cryptの導入者からパスワードを共有してもらい、それを入力する。

キーペアを鍵束にインポートしたメンバーは、既述の鍵の信用設定を行い、対象となるgit-cryptを使っているGitリポジトリをクローンし、リポジトリのルートディレクトリで以下のコマンドを実行。

$ git-crypt unlock

ここでもパスフレーズを求められるので、git-cryptの導入者が設定したパスフレーズを入力すれば、各自の環境におけるgit-cryptの設定が完了する。

このGPGのキーペア自体を共有する場合だと、結局、秘密鍵パスフレーズを共有しなければならないので、対称鍵を直に共有するのと安全度合い的にはあまり変わりが無い様な感じもするかもしれないが、暗号化した対称鍵をGitリポジトリで管理するという点が異なるので、対称鍵を紛失するリスクを減らせるという点では、こちらの方が安全ではある。

Docker Desktop for MACのDockerホストの仮想マシン(HyperkitのVM)に入りたい

Dockerでローカルストレージの名前付きボリュームを作成した際に、マウントポイントの実体を確認したかった。

ただそれだけ。

環境

ボリュームを作成する

まず、適当なローカルストレージのボリュームを作成する。

$ docker volume create sample
sample

作成したボリュームをinspectしてマウントポイントを確認。

$ docker volume inspect sample
[
    {
        "CreatedAt": "2021-10-23T15:57:48Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/sample/_data",
        "Name": "sample",
        "Options": {},
        "Scope": "local"
    }
]

ボリュームの実体は/var/lib/docker/volumes/sample/_dataにある事が分かった。

ただ、このパスはDockerホストが稼働している仮想マシン上に存在する為、ターミナルで普通に探しても見つからない。

$ ls /var/lib/docker/volumes/sample/_data
ls: /var/lib/docker/volumes/sample/_data: No such file or directory

Docker Desktop for MACは、HyperkitというmacOSのHypervisor.frameworkのみをサポートしているアプリケーションにHypervisorの機能を組み込むツールを利用しており、DockerホストはこのHyperkitの仮想マシンLinuxkitを使って構成したコンテナランタイム環境(containerd&runc)で動いている。

その為、上述のマウントポイントの実体を確認するには、Dockerホストが稼働している仮想マシンに入る必要がある。

で、Dockerホストに入る方法を調べてみると、以下の様なscreenコマンドを使ってDockerホストのttyにアクセスする方法が出てくるのだが、

$ screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty

自分の環境ではパーミッションエラーとなり、rootでもパーミッションを変更出来なかった為、この方法では無理だった。

その為、別の方法を探していたところ、nsenterを使って特権モードのコンテナを起動することで、Dockerホストに入ることが出来ると分かった。

nsenterを利用すると、docker execとは異なり、cgroupに縛られることなく、指定のコンテナのプロセス空間に対して、外から新しいプロセスを生成出来るようになる。

nsenterコマンドはalpineにインストールされているので、以下の様なコマンドを実行することで、Dockerホストに入ることが可能となる。

$ docker run -it --rm --privileged --pid=host alpine:edge nsenter -t 1 -m -u -n -i sh
/ # 

--pidにhostを指定してコンテナ内からDockerホストのプロセスを見えるようにし、--privilegedでDockerホストリソースへのアクセスを許可することで、nsenterを使ってDockerホスト側のプロセス空間にshプロセスを生成している訳である。

これで、Dockerホストに入ってボリュームのマウントポイントの実体を確認することが出来た。

$ docker run -it --rm --privileged --pid=host alpine:edge nsenter -t 1 -m -u -n -i sh
/ # ls -al /var/lib/docker/volumes/sample/_data
total 8
drwxr-xr-x    2 root     root          4096 Oct 23 15:57 .
drwx-----x    3 root     root          4096 Oct 23 15:57 ..
/ #

ちなみに、nsenterはalpineのみならず、debianubuntucentos等、大概のコンテナOSイメージにはインストールされているので、それらのイメージを使っても同様にDockerホストへのアクセスは可能。

また、調べていたらnsenter1という、nsenterのコマンド入力を省略するイメージも存在していたので、こっちを使っても良いかも。

$ docker run -it --rm --privileged --pid=host justincormack/nsenter1
/ #

Ansible Night in Tokyo 2018.04に参加してきた

RedHat社のセミナールームで開催されたAnsible Night in Tokyo 2018.04に参加してきました。

ansible-users.connpass.com

Ansibleユーザー会主催のイベントに参加するのは第1回もくもく会以来。

80名の参加枠に対して240名くらいの応募という人気っぷりで、抽選の結果、見事に外れた上、補欠順位も200番以降となってしまい、これは絶望的だなぁと一時は落胆したものの、ブログ枠が空いていたので滑り込んだ次第です。

そんな訳で、各講演を拝聴しての雑感を書き残しておきます。

Cisco with Ansible

シスコシステムズ加藤久慶さん、横石 雄大さん、畝高 孝雄さんの講演。お三方それぞれのテーマで発表。

NexusでAnsibleやってみた

まず、Ciscoについて。日本ではルーターやスイッチのイメージ強いけど、それらは一部のサービスで、ネットワークに関わる様々な製品を提供しているとのこと。

この発表ではCiscoのスイッチNexusシリーズ4台を使ったネットワークを、Ansibleで自動的に構築(スイッチ間でのP2Pセグメント設定、Loopbackインターフェースの作成、OSPFを有効にしての経路伝播等)するところをサクッとデモされていました。

NexusシリーズのOSであるNX-OS用のAnsibleモジュールは現在72種類あり、大概のことは自動化できるそうです。

なお、CiscoにはDevNetという開発者向けのサービスがあり、そちらに各種サービスのSandboxが提供されているので、実機の購入という高いハードルを越えずとも、気軽に検証することが可能とのこと(DevNetは様々なSSOに対応しており、GithubFacebook等のアカウントでログインできます)。

また、Learning Labsというコンテンツもあり、Cisco製品におけるAnsibleの活用方法や、Ansible自体の使い方等について学習することができる(Ansible関連以外のものも)ので、是非、有効に活用してもらいたいとのことでした。

Contiv + k8s + Ansible

Contivについての紹介がメインな発表。メモはとったものの、発表内容の要点はCiscoのブログにまとまっていたので、そちらの方が参考になります。

実務でコンテナ使えていないこともあって、正直、Contivについては全く知らなかったのだけれど、深掘りしたい内容でした。

Cisco ACIとAnsibleのステキな関係

www.slideshare.net

Ansibleの制御対象は増えるほど管理が大変。サーバーという点に対し、面であるネットワークの構成管理は勝手が違う。

という問題に対し、ACI(+APIC)の紹介をメインに、Ansibleとの連携でネットワーク構成管理の煩雑さがどう解消されるのかといった発表でした(多分)。ACI(+APIC)については自分のメモよりCiscoの製品紹介を見た方が参考になります。

ACIのAnsibleモジュールは、充実したドキュメントが公式に用意されているので、検証する際はそちらを参照すると良いとのこと。

なお、ACIにはacitoolkitというPython製のツール群があり、その内のACI Diagram generatorを利用すると、APICAPIアクセスしてACIのダイアグラムをグラフィカルに作成することができるのだとか。

Ansible2.5のアップデートとネットワーク自動化

RedHat社のAnsibleビジネスユニット プリンシパル・プロダクト・マネージャー、Sean Cavanaughさんの講演。

英語で通訳無しであった為、残念ながらあまり理解できませんでしたが、概ね以下のようなお話をされていたかと思います。

Ansibleを追いかける際の情報源を知れたのは収穫でした。

LT1:ANSIBLE ROLEの継続的自動UPDATE

chrojuさんの発表。

speakerdeck.com

Ansible Roleをソフトウェアパッケージに見立て、yarnやbundle、Gemfile.lock等を参考に工夫を凝らしてCIを回すというお話。

個人的にAnsibleはまだまだミニマムな使い方しかしていないけれど、ゆくゆくはぶつかりそうな問題なので参考になりました。

LT2:Junos モジュールのコネクションタイプの使い分け

akira6592さんの発表。

www.slideshare.net

英語の講演中に理解しきれなかった2.5から追加されたコネクションタイプについて、こちらのLTで補完されました。

LT3:Ansibleを使用したWindows管理

curry9999さんの発表。

speakerdeck.com

なかなか出来上がった状態での発表となったcurry9999さん。笑いあり介護ありで面白かったですw

AnsibleのWindowsモジュールは1.7からじわじわ増え、2.5では81種類となり、自動化できる範囲も広がっているので、積極的に活用して無駄な運用タスクを減らしていこうというお話。

curry9999さんはライフワーク(?)でAnsibleモジュールの歴史をまとめられているので、定期的にチェックさせてもらっています。

Ansible 2.6 対応 モジュールの歴史&nbsp;フルアーマー版awsbloglink.wordpress.com

LT4:Ansible とStackStorm でつくるChatOps 環境

katsuhisaさんの発表。

speakerdeck.com

StackStormを活用したChatOpsの自動化について。

運用においてChatが有効活用できていない環境にいるので、ここまで自動化できてるのは個人的には未来感ありました。

IFTTTって知らなかった。トライしたい。

LT5:Windowsのcp932に苦闘している

Hidetoshi Hirokawaさんの発表。

www.slideshare.net

AnsibleでWindowsの自動化を進めていくとぶち当たる、文字コードという特有の問題に対するお話。

Windows文字コード問題は本当に苦労しますね…。

終わりに

知見の乏しいネットワーク領域に関する講演がメインであったので、その場では理解しきれないことも多かったのですが、日頃、サーバー用途でしかAnsibleを使っていない自分にとっては、全体的に新鮮な内容でありました。改めてAnsibleの適用範囲って広い。

なお、イベント終了後は恒例となっているAnsible飯に参加させて頂き、Ansibleに関する話題は当然として、バーベキューとか肉の妖精とかIoTプラレールとか、参加者の皆さんの興味深い趣味の話にも花が咲き、今回も有意義な時間を過ごさせてもらいました。

イベント主催者、スタッフの皆さん、RedHat社に感謝致します。有難うございました。

※ 会場が恵比寿だからか、イベント開始前にRedHat社の望月社長からヱビスビールが振る舞われました。ありがたやありがたや。

※ ブログ書くということでAnsibleノートも頂きました。ありがたやありがたや。

PackerでAMIを作ろうとしたら吐かれたsudoエラーについて

久々にPackerを使ってみて遭遇したエラーについてメモしておく。

環境

動作環境はMac Book AirOSX 10.8 Mountain Lion。Packerはv0.8.6を使用。
AMIにはAmazon Linux AMI 2015.09.1 (HVM), SSD Volume Type - ami-383c1956を選択。

Packerテンプレート

単純にAmazon LinuxのEC2インスタンスsudo yum update -yしたAMIを作るだけのものである。

{
  "variables": {
    "aws_access_key": "",
    "aws_secret_key": ""
  },

  "builders": [{
    "type": "amazon-ebs",
    "access_key": "{{user `aws_access_key`}}",
    "secret_key": "{{user `aws_secret_key`}}",
    "region": "ap-northeast-1",
    "source_ami": "ami-383c1956",
    "instance_type": "t2.micro",
    "ami_name": "wps-web-ami {{timestamp}}",
    "ssh_username": "ec2-user",
    "ssh_timeout": "5m",
    "tags": {
      "Name": "WordPress Server"
    }
  }],

  "provisioners": [{
    "type": "shell",
    "inline": [
      "sudo yum update -y"
    ]
  }]
}

エラーメッセージ

上記のテンプレートでビルドしたら以下の様なメッセージを吐いてコケた。

$ packer build ami.json 
amazon-ebs output will be in this color.

==> amazon-ebs: Prevalidating AMI Name...
==> amazon-ebs: Inspecting the source AMI...
==> amazon-ebs: Creating temporary keypair: packer 5655d9e2-b5e7-8a86-9f64-33936ce5add0
==> amazon-ebs: Creating temporary security group for this instance...
==> amazon-ebs: Authorizing access to port 22 the temporary security group...
==> amazon-ebs: Launching a source AWS instance...
    amazon-ebs: Instance ID: i-ed34aa48
==> amazon-ebs: Waiting for instance (i-ed34aa48) to become ready...
==> amazon-ebs: Waiting for SSH to become available...
==> amazon-ebs: Connected to SSH!
==> amazon-ebs: Provisioning with shell script: /var/folders/_p/5nbnyk0n5x599chrtk9vswqc0000gn/T/packer-shell560434101
    amazon-ebs: sudo: sorry, you must have a tty to run sudo
==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: No AMIs to cleanup
==> amazon-ebs: Deleting temporary security group...
==> amazon-ebs: Deleting temporary keypair...
Build 'amazon-ebs' errored: Script exited with non-zero exit status: 1

==> Some builds didn't complete successfully and had errors:
--> amazon-ebs: Script exited with non-zero exit status: 1

==> Builds finished but no artifacts were created.

原因と解決方法

エラーメッセージの赤く着色した部分が問題なのだが、読んだ通りで仮想端末を使わなければsudoできませんよと言われている。
一年くらい前にPackerで同じ様にAMIを作っていた時には、この設定内容で問題無かったような気がしたのだが、どういうことだろうと思い調べてみたところ、PackerのChangeLogにその答えが書いてあるのを見つけた。

core: SSH connection will no longer request a PTY by default. This can be enabled per builder.

Packerは2015年6月23日にv0.8.0へとアップデートしたのだが、その際、標準ではSSH接続にPTYを要求しなくなったそうだ。要するに、リモートマシンに仮想端末でログインせず、直接コマンドを投げているので、sudoersに外部からのコマンド実行を遮断されている訳である。
この問題を解決するのは簡単で、SSH接続にPTYを要求するよう設定してやれば良い。v0.8.2から追加されたCommunicatorのオプションであるssh_ptytrueを設定し、上記テンプレートのBuilder部分に追記してやると、SSH接続に仮想端末を使うようになるので、Provisionerのsudoコマンドが実行されるようになる。
なお、他の解決方法として、AMI Builderのuser_dataを利用し、sudoersの設定内容を書き換えてしまうということも可能ではあるのだが、当然、セキュリティ的に問題があるのでおすすめはしない。素直にssh_ptyを使った方が手間が無いし安全だろう。

ChefのパッケージをWeb API(Omnitruck API)で取得する

Chefのパッケージ取得方法について、ちょっとしたメモ。
Chef ClientやChef Serverのパッケージは、ダウンロードページから以外にも、Web APIを利用した取得方法が存在する。

Omnitruck API

Chef社はOmnitruck APIというWeb APIを公開しており、任意のURLをリクエストすることにより、リリースされているあらゆるバージョンのChef ClientやChef Serverのパッケージを取得することができる。
また、通常のダウンロードページには存在しない、プレリリース版やナイトリー版の取得にも対応していたりする。
Chef ServerのCommunity Cookbookなんかでは、OhaiとOmnitruck APIを利用して、環境に合わせた臨機応変なパッケージの取得を実現している。

Chef Clientの取得方法

以下のURLをリクエストすることで、パッケージを取得できる。

http://www.getchef.com/chef/download?p=$PLATFORM&pv=$PLATFORM_VERSION&m=$MACHINE_ARCH&v=latest&prerelease=false

また、上記URLのdawnloadをmetadataに変更すると、パッケージに付随したメタデータを取得することができる。

http://www.getchef.com/chef/metadata?p=$PLATFORM&pv=$PLATFORM_VERSION&m=$MACHINE_ARCH&v=latest&prerelease=false

メタデータは、パッケージのダウンロードURL、MD5とSHA256のチェックサムが記されたタブ区切りのテキストデータである。

url http://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chef-11.16.0-1.el6.x86_64.rpm
md5 5c8cfdbab2684148e2bb859b736b6827
sha256 e4d0236cc495d080f8e7a01704e2ef554e12088687e4fe946ee8027b79871bbb 

クエリパラメーターについては、

  • pはプラットフォーム。debian、el(rhel系)、freebsdmac_os_x、solaris2、sles(SUSE Enterprise Linux Server)、suseubuntuwindowsといった値を指定する。
  • pvはプラットフォームバージョン。プラットフォームに応じて指定できる値は決められており、elであれば5や6、ubuntuであれば10.4や12.10等、mac_os_xであれば10.6や10.7等といった具合。
  • mはマシンアーキテクチャi386i686x86_64、amd64といった値を指定するが、これもプラットフォームに依存する。
  • vはChef Clientのバージョン。デフォルトはlatestで省略可能。特定のバージョンが欲しい場合は、Semantic Versioningに則った形式で、x.y.z(x=MAJOR、y=MINOR、z=PATCH)といった具合に指定する。
  • prereleaseはプレリリース版を取得するためのフラグ。デフォルトはfalseで省略可能。

といった感じ。
これらクエリパラメーターでサポートされている値のより詳細な情報は、公式のドキュメントの方を参照してほしい。

Chef Serverの取得方法

Chef ClientのダウンロードURL末尾に-serverを付与するとChef ServerのダウンロードURLとなる。

http://www.getchef.com/chef/download-server?p=$PLATFORM&pv=$PLATFORM_VERSION&m=$MACHINE_ARCH&v=latest&prerelease=false&nightlies=false

メタデータの取得URLも同様。

http://www.getchef.com/chef/metadata-server?p=$PLATFORM&pv=$PLATFORM_VERSION&m=$MACHINE_ARCH&v=latest&prerelease=false&nightlies=false

クエリパラメーターも基本的にChef Clientと同じ構成であるが、フラグが一つ追加されている。

  • nightliesはナイトリー版を取得するためのフラグ。デフォルトはfalseで省略可能。ナイトリー版はあくまで検証用として用意されているので、本番環境では決して使わないこと。

当然だが各クエリパラメーターで指定できる値はChef Clientとは異なるので、サポートされている値の詳細な情報は、公式のドキュメントの方を参照してほしい。
公式ドキュメントには、他にも取得例が記載されているので、自前でChef ClientやChef Serverのインストール自動化プログラムを作る際には参考になるだろう。

ドメインについて

最後に、Chef社の旧ドメインについても触れておく。
現在のChef社は、社名変更に伴ってgetchef.comドメインを使っているが、変更前のOpscode社時代ではopscode.comドメインが使われていた。
このドメインはまだ生きており、opscode.comにアクセスすると、getchef.comへとリダイレクトされることが分かる。
で、Omnitruck APIについてだが、こちらも以前のURLであるwww.opscode.comでリクエストしても、www.getchef.comでリクエストした場合と同様に、正常にパッケージを取得することができる。
ちなみに、冒頭で例に挙げたChef ServerのCommunity Cookbookなんかは、このエントリを書いた時点では、旧ドメインのままだったりする。
とはいえ、いずれはサポートの切れるかもしれないドメインではあるので、これからOmnitruck APIを利用する場合に、わざわざ旧ドメインAPIを使用するのは止めておいた方が良いだろう。

CentOS6.5でランダムSalt付きSHA-512のシャドウパスワードを生成する

CentOS6.5でランダムSalt付きSHA-512のシャドウパスワードを生成する方法を調べたのでメモしとく。

最初、OpenSSLでできるかなと思いついたが、openssl passwdMD5はいけるけど、SHAには対応しておらず駄目だった。

$ openssl passwd --help
Usage: passwd [options] [passwords]
where options are
-crypt             standard Unix password algorithm (default)
-1                 MD5-based password algorithm
-apr1              MD5-based password algorithm, Apache variant
-salt string       use provided salt
-in file           read passwords from file
-stdin             read passwords from stdin
-noverify          never verify when reading password from terminal
-quiet             no warnings
-table             format output as table
-reverse           switch table columns

他にその手のツールはないか調べたところ、要件にピッタリ合致するgrub-cryptコマンドというのを見つけた。

$ grub-crypt --help
Usage: grub-crypt [OPTION]...
Encrypt a password.

  -h, --help              Print this message and exit
  -v, --version           Print the version information and exit
  --md5                   Use MD5 to encrypt the password
  --sha-256               Use SHA-256 to encrypt the password
  --sha-512               Use SHA-512 to encrypt the password (default)

Report bugs to <bug-grub@gnu.org>.
EOF

このコマンドを使うと、以下のように対話式でランダムSalt付きのSHA-512シャドウパスワードが生成できる。

$ grub-crypt         ←デフォルトがSHA-512なのでオプション必要無し
Password:            ←パスワード入力(今回はsampleという文字列)
Retype password:     ←もう一度パスワード入力
$6$5TIs9aRT3V4IRwJz$guTjCJzy1k.t8Gy8Y0TQiY25S7y6ptVzxeS0/o1JJG52Xv32lVIGCqOh11QCSeTqSlR2CVI380kTHYEY6WWOq/

うんうん、ちゃんとシャドウパスワードの形式で出力されてるね。
とてもシンプルで良いコマンドです。

Cygwinをアンインストールする

Cygwinをアンインストールしようと思ったが、Cygwinにはアンインストールを自動で行う手段が無く、手作業で行う必要があったので、その手順をメモしておく。

アンインストール手順

手順は公式サイトのFAQに記載されている。

http://cygwin.com/faq/faq.html#faq.setup.uninstall-all

意訳すると、

  1. Cygwin内でサービスを起動している場合は以下の手順で全て削除しましょう。一般的にインストールされていそうなサービスはsshd、cron、cygserver、inetd、apachepostgresqlとかです。

    1. cygrunsrv -Lで登録しているサービスを確認します。cygrunsrvが無い場合はこの過程を飛ばしましょう。

    2. 起動しているサービスがあればcygrunsrv --stop service_nameで停止します。inetdを使ってスタンドアローンなサービスを起動している場合はcygrunsrv -Lで表示されませんが、cygrunsrv --stop inetdを実行すればそれらもまとめて停止します。

    3. 最後にcygrunsrv --remove service_nameで各サービスを削除しましょう。

  2. X11サーバーが起動していれば停止し、バックグラウンドで動いているCygwinプログラムも止めます。コマンドプロンプトを終了し、Cygwinプロセスが無い事を確認しましょう。もし、再インストールする時の為にマウントポイントを保存しておきたければ、mount -mでfstabに書き込んでおくと良いでしょう。

  3. cyglsa.dllをインストールしており、/usr/bin/cyglsa-configを実行していた場合、LSA authentication packageの使用を停止する必要があります。その為、レジストリの/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Lsa/Authentication Packagesの値を、元のmsv1_0という値に戻してWindowsを再起動しましょう。

  4. Cygwinのルートフォルダとサブフォルダを全て削除します。オブジェクトが使用されているといったエラーが出ましたら、全てのサービスが停止されて、全てのCygwinプログラムが終了しているかを確認しましょう。パーミッションエラーが出ましたら、エラーの原因となっているファイルやフォルダのパーミッションを変更しましょう。例えば、システムサービスによって使用されているファイルはSYSTEMアカウントが保持し、一般ユーザーからは書き込みができなくなります。

    手っ取り早く削除するには、自分に全てのファイルとフォルダの所有権限を付与しましょう。Windows Explorerを開き、Cygwinのルートフォルダで右クリックし、プロパティからセキュリティタブを選択します。もし、Windows XP Home Editionのシンプルファイル共有を使っているならば、これはセーフモードにしてからやる必要があります。それから、自分のアカウントを選択し、フルコントロールできるように変更すればOKです。まとめて削除できるようになるでしょう。

  5. デスクトップとスタートメニューのショートカット、setup-x86{_64}.exeがインストール時に使ったダウンロードフォルダを削除します。しかし、再インストールする場合であれば、setup-x86{_64}.exeは既にあるダウンロードフォルダをキャッシュとして再利用できるので、残しておくと再ダウンロードせずに済むでしょう。

  6. システムパスにCygwinを通していたら、同じ場所に再インストールする予定が無い限りは削除しましょう。CYGWIN環境変数も同様です。

  7. 最後に、徹底的にCygwinの痕跡を消したければ、レジストリのHKEY_LOCAL_MACHINEとHKEY_CURRENT_USER配下にある、Software/Cygwinを削除しましょう。しかしながら、ここまでの手順に従っていれば、既に削除すべきものは削除できています。通常、インストールフォルダは全てのレジストリに保持されています。

と、まあこんな感じか。

で、この通りにやって特に問題無くアンインストールできました。