GCEでライブパッチは使えなさそう。

手元の端末でcanonical-livepatchが動いてるのを見て、そういえば3台までいけるんだからサーバでも使おうか、と思った。

$ uname -a
Linux yumenosora 4.15.0-1024-gcp #25~16.04.2-Ubuntu SMP Tue Oct 30 14:14:10 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ sudo snap install canonical-livepatch
canonical-livepatch 8.0.6 from 'canonical' installed
$ sudo canonical-livepatch enable [トークン]
2018/11/19 14:20:31 cannot use livepatch: your kernel "4.15.0-1024-gcp" is not eligible for livepatch updates

にゃうーん。Compute Engine上では専用のカーネルが使われるけど、ソレにライブパッチは使えない、みたい。残念。

さよならはてなダイアリー。

はてダからの移行作業を行いました。混んでて中断されてるって話を聞いてたから今までやらなかったんだけど、そろそろほとぼりも冷めたんかな。さほど記事数が無いからっていうのもあると思うけど、30分程度でインポート完了。
一時期に比べて書く量はすごい減ったけど、これからはこっちでいろいろと書いていきます。

DNS over HTTPSで名前解決を保護する。

角川の金盾の件も頭の片隅には置きつつ、それ以前に、名前解決が平文で行われるのはセキュアではないよね、と思ったので、最近話題のDNS over HTTPSを使って名前解決が出来るようにしてみる。
環境はUbuntu 18.04 LTS。
まずはdnscrpyt-proxyをインストールする。

sudo add-apt-repository ppa:shevchuk/dnscrypt-proxy
sudo apt install dnscrypt-proxy

で、設定ファイルを変更。
/etc/dnscrypt-proxy/dnscrypt-proxy.toml

--- dnscrypt-proxy.toml.orig	2018-10-16 21:15:17.821726742 +0900
+++ dnscrypt-proxy.toml	2018-10-16 21:23:20.394256628 +0900
@@ -27,13 +27,13 @@
 ## The proxy will automatically pick the fastest, working servers from the list.
 ## Remove the leading # first to enable this; lines starting with # are ignored.
 
-# server_names = ['scaleway-fr', 'google', 'yandex', 'cloudflare']
+server_names = ['google', 'cloudflare']
 
 
 ## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
 ## Note: When using systemd socket activation, choose an empty set (i.e. [] ).
 
-listen_addresses = []
+listen_addresses = ['127.0.0.1:53']

server_namesはお好みで。GoogleのとCloudflareのがあればいいだろうって判断したけど、検閲絡みのハナシを考えるとscaleway-fr(フランス?)とかyandex(ロシア)のも入れておいたほうがいいのかな。とはいえ起動時のRTT判定で十中八九Cloudflareが選択されるので変化はないかも。
このままでは起動しなかったので、systemdのUnitファイルにちょっと書き足す。
/lib/systemd/system/dnscrypt-proxy.service

--- dnscrypt-proxy.service.orig	2018-10-16 21:16:23.818348613 +0900
+++ dnscrypt-proxy.service	2018-10-16 23:09:48.422039898 +0900
@@ -20,6 +20,7 @@
 CacheDirectory=dnscrypt-proxy
 LogsDirectory=dnscrypt-proxy
 RuntimeDirectory=dnscrypt-proxy
+AmbientCapabilities=CAP_NET_BIND_SERVICE
 
 [Install]
 Also=dnscrypt-proxy.socket

この変更入れないと、DynamicUser=yesだから一般ユーザとして起動するのに、53番をlistenしようとしてコケるんだよね。
で、systemd-resolvedを殺す。

sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved

最後に、名前解決をlocalhostでやるようにする。

$ cat /etc/resolv.conf
nameserver 127.0.0.1:53

再起動して完了。システムごとでもいいし、サービス再起動でも動くはず。

sudo systemctl restart dnscrypt-proxy
sudo systemctl restart NetworkManager

震災から22年。

去年の記事から先、何も書いてなかったとは……。
例年通り、非常用のやつのチェックをしておきましょっか。
最近はローリングストック法とゆうのが人気なようで。どうせ使う消耗品ならその方が手頃だからねぇ。更新忘れ対策にはGoogleのリマインダを使えばいい。今持ってるアルファ化米の期限切れ後はウチでもそうしよっかな。

PGroongaのインデックスを常に使う方法。

PGroongaJSON(B)に対しても全文検索できるのが便利ですが、レコード数が少ないとこんな感じで困ったことになる。
チュートリアルにあるサンプルスキーマとデータを投入した状態で、

test=# SELECT record FROM logs WHERE record @@ 'paths @ ".code" && number >= 200 && number < 300';
ERROR:  pgroonga: operator @@ is available only in index scans

レコード数が少ないので全件舐めたほうが速いからプランナがインデックスを使おうとせずにこうなる。

test=# explain SELECT record FROM logs WHERE record @@ 'paths @ ".code" && number >= 200 && number < 300';
                                   QUERY PLAN                                   
--------------------------------------------------------------------------------
 Seq Scan on logs  (cost=0.00..26.38 rows=655 width=32)
   Filter: (record @@ 'paths @ ".code" && number >= 200 && number < 300'::text)
(2 rows)

チュートリアルにあるとおり、

SET enable_seqscan = off;

すれば動くけど、本番でこれやるのはちょっとどうかと。かと言って、レコード数が増えてきてからPGroongaを使うようにアプリケーションを改修するっていうのも乗り気がしない。最初から@@演算子を使ったクエリを書きたい。


ってことでどうするか。要は常にインデックスを使うようにすればいいので、pg_hint_planを使う。
インストールした上で、クエリにヒント句を足してやるだけ。

test=# /*+ IndexScan(logs) */ SELECT record FROM logs WHERE record @@ 'paths @ ".code" && number >= 200 && number < 300';

record                                            
----------------------------------------------------------------------------------------------
 {"code": 200, "host": "www.example.com", "tags": ["web", "example.com"], "message": "GET /"}
(1 row)

これでレコードが1つしかなかろうが常にインデックスが使用され、@@演算子を使ったクエリが常に通るようになる。

BDへの安全なバックアップ方法。


というのを契機にしてバックアップ方法を再考してたんですが、堅牢なBD書き出し方法を考えたので書き留めます。

要求

  • メディアの劣化・破損の対策を講じる
  • メディアが第三者に渡った場合のデータ漏洩を防止する
  • 利便性のため、ディスクから直接ファイルを読み出せる
  • アクセスに必要なツールはすべてフリーソフトで構成されていること

構成

上記の要求を踏まえ、このような構成でディスクを作成することにしました。

  1. ファイルをEXT4フォーマットのイメージに格納(a)
  2. イメージはLUKSにて暗号化
  3. イメージをBDに書き出す際、エラー訂正情報を付与する

依存

  • cryptsetup
  • dvdisaster
  • mdadm

作成手順

EXT4ディスクイメージの作成
cd /tmp
dd if=/dev/zero bs=1M count=3500 of=disk.img.0
dd if=/dev/zero bs=1M count=3500 of=disk.img.1
dd if=/dev/zero bs=1M count=3500 of=disk.img.2
dd if=/dev/zero bs=1M count=3500 of=disk.img.3
dd if=/dev/zero bs=1M count=3500 of=disk.img.4

sudo losetup /dev/loop0 disk.img.0
sudo losetup /dev/loop1 disk.img.1
sudo losetup /dev/loop2 disk.img.2
sudo losetup /dev/loop3 disk.img.3
sudo losetup /dev/loop4 disk.img.4

sudo mdadm --create /dev/md/md0 -l linear -n 5 /dev/loop0 /dev/loop1 /dev/loop2 /dev/loop3 /dev/loop4
sudo cryptsetup luksFormat /dev/md/md0
sudo cryptsetup luksOpen /dev/md/md0 disk
sudo mkfs.ext4 /dev/mapper/disk
mkdir mount
sudo mount /dev/mapper/disk mount
sudo chown USERNAME mount

単一のrawイメージではなく複数のイメージをRAID0で束ねているのは、ISO9660フォーマットの仕様上4GB以上のファイルを格納できないため。単一イメージにしてしまうとファイル分割の必要がある。

ディスクイメージにファイルを投入

/tmp/mountに書き出したいファイルをコピーする

ISOイメージを作成
sudo umount mount
sudo cryptsetup luksClose disk
sudo mdadm --stop /dev/md/md0
sudo losetup -d /dev/loop0
sudo losetup -d /dev/loop1
sudo losetup -d /dev/loop2
sudo losetup -d /dev/loop3
sudo losetup -d /dev/loop4
mkisofs -L -R -o disk.iso -V DISKNAME disk.img.*
dvdisaster -c -i disk.iso -mRS02 -n BD

上記のパラメータだと、30%ほどの冗長性が確保できる。あとは作成したISOイメージをBD-Rに書き出せばよい。

マウント方法
sudo losetup /dev/loop0 /path/to/disk.img.0
sudo losetup /dev/loop1 /path/to/disk.img.1
sudo losetup /dev/loop1 /path/to/disk.img.2
sudo losetup /dev/loop1 /path/to/disk.img.3
sudo losetup /dev/loop1 /path/to/disk.img.4
sudo mdadm --assemble --force /dev/md/md0 /dev/loop0 /dev/loop1 /dev/loop2 /dev/loop3 /dev/loop4
sudo cryptsetup luksOpen /dev/md/md0 disk
mkdir /tmp/mount
sudo mount /dev/mapper/disk /tmp/mount