Mazn.net

やってみて 調べてみて 苦労しなけりゃ 箱は動かじ

Thunderbird で表示される絵文字を無効化

いつ頃からか、メールソフトのThunderbirdでメールを開くと、: ) のような文字が、😊 という絵文字で表示されるようになりました。この表示を元に戻す方法の紹介です。今回調査に使用したThunerbirdのバージョンは、68.12.0 です。

Thunderbird のメニューバーから、ツール⇒オプションを選びます。

さらに表示というメニューを選択すると、「顔文字をアイコンで表示する」というチェックボックスがあるので、このチェックを外すと、😊 が : ) という表示に戻りました。

以上です。

find コマンドで全てのファイルにマッチしない!

Linuxでファイル検索する場合の基本コマンドに、「find」があります。ファイル名に含まれる文字列の一部を検索したりできるのですが、検索条件をちょっと間違えるだけで、目的のファイルが見つからなく(マッチしなく)なるので、注意が必要です。

例えば、以下の構成のディレクトリとファイルがあるとします。

# tree -F root
root/
└── my-dir/
    ├── dir1/
    │   └── memo2.txt
    ├── dir2/
    │   └── memo2.txt
    └── memo.txt

この時、拡張子が .txt のファイルを探したいとします。root というディレクトリ内で以下のfindを実行してみます。

# cd root/
# find . -name *txt
./my-dir/dir2/memo2.txt
./my-dir/memo.txt
./my-dir/dir1/memo2.txt

目的の .txt 拡張子のファイルが全てマッチしました。

では、my-dir ディレクトリの中で同じコマンドを実行するとどうなるでしょうか?

# cd my-dir/
# find . -name *txt
./memo.txt

このように、memo.txt しかマッチしなくなりました。なぜ、このような事象が起きてしまうのでしょうか? 実は、今回このコマンドを実行しているシェル(bash)の仕様が関係しているのです。

bash でのアスタリスク 「* 」はワイルドカード展開を意味します。つまり、カレントディレクトリに *txt にマッチするファイルがあると、コマンド実行前にそのファイル名に置き換えられるわけです。実際にコマンドを叩いて試してみます。

上記ディレクトリ構成で、root ディレクトリ内で、echo *txt を実行してみます。

# cd root
# echo *txt
*txt

my-dir ディレクトリでも同様にechoを実行してみます。

# cd my-dir/
# echo *txt
memo.txt

このように、root ディレクトリ内には、*txt にマッチするファイルがないので、アスタリスクが置き換わらず、echo 出力に *txt と表示されましたが、my-dir ディレクトリ内には、memo.txt というファイルがあるので、echo出力は、memo.txt に置き換わってしまいました。

つまり、my-dir 内でfindを実行した場合、

# find . -name *txt

# find . -name memo.txt

を実行していることになり、結果、memo.txt にしかマッチしないという悲劇を生み出すわけです。ここまで理解できれば、対処方法は簡単です。シェルにアスタリクスを処理させなければよいわけです。例えば、アスタリクスをエスケープ(\)すると、マッチするようになります。

# find . -name \*txt
./dir2/memo2.txt
./memo.txt
./dir1/memo2.txt

ただ、この方法は面倒だと思うので、シングルクォートで囲む方が一般的だと思います。

# find . -name '*txt'
./dir2/memo2.txt
./memo.txt
./dir1/memo2.txt

以上findのちょっとしたtipsでした。

find でファイル名の文字列検索時は、
必ずシングルクォートで囲みましょう!

k8s Nginx Ingress ControllerでWAF

セキュリティを考慮したKubernetesのNginx Ingress ControllerのIngress設定例です。
※ これが完璧な設定というわけではなく、あくまで一設定例です。

難しい設定はspecに書けないので、以下のようにannotationsに書きます。server_tokens でNginxのバージョン情報を隠してます。

さらにModSecurityを用いてWAFを構築しています。WAFのルールにはOWASPを使いつつ、自分のルールも書けるようにしています。

tlsやrulesの設定は環境に合わせて適宜修正してください。

---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  namespace: myapp
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
    server_tokens off;
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/enable-modsecurity: "true"
    nginx.ingress.kubernetes.io/modsecurity-transaction-id: "$request_id"
    nginx.ingress.kubernetes.io/modsecurity-snippet: |
      SecRuleEngine On
      SecRequestBodyAccess On
      SecAuditEngine RelevantOnly
      SecAuditLogParts ABIJDEFHKZ
      SecAuditLog /var/log/modsec_audit.log
      SecDebugLog /var/log/modsec_audit_debug.log
      Include /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf
spec:
  tls:
  - hosts:
    - example.com
    secretName: example-com-tls-secret
  rules:
  - host: example.com
    http:
      paths:
        - path: /
          backend:
            serviceName: my-service
            servicePort: 80

自分のルールを書きたい場合は、Include /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf の前後辺りに書くと良いでしょう。例えば、myconf.php へのアクセスを防ぎたいなら以下のような設定になると思います。

      Include /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf
      SecRule REQUEST_URI "myconf.php" "id:500001,phase:2,deny,log,status:405"

IPアドレス計算に使えるLinuxコマンド ipcount ipcalc sipcalc

以前、コマンドラインでIP計算に使えるコマンドとして、perl-Net-IPというパッケージに入ってる ipcountを紹介しました。これ以外にも、ipcalc や sipcalc というIP計算に使えるコマンドがあるので紹介します。
※ 環境にコマンドが入ってない場合は、apt や dnf, yum 等のコマンドで簡単にインストールできると思います。

まず最初に、ipcount, ipcalc, sipcalc の使い分けですが、ざっくり書くとこのような感じです。

  • ipcount
    • IPの範囲 (最初のIPと最後のIP) に関する計算ができます。範囲からホストアドレスやプレフィックスを計算したり、その範囲のIPの数などが簡単に分かります。
  • ipcalc
    • 与えられたIPの情報を表示できます。また、IP の表記が間違ってないかのチェックや、IPからホスト名の逆引きなどもできます。
  • sipcalc
    • ipcalcの高機能版と言われてますが、どちからというとipcalcよりIPの詳細情報を表示するコマンドというイメージで、IPの表記を2, 10, 16進数に変換することができます。ipcalcと互換性はなく、ipcalcでできるホスト名逆引きなどはできません。

ipcount

ネットワークアドレスとプレフィックスを指定すると、IPの範囲が分かります。

# 192.168.0/24 192.168.0.0 - 192.168.0.255 [256]ipcount 192.168.0.0/24
192.168.0/24 192.168.0.0 - 192.168.0.255 [256]

IPの範囲を以下のようにハイフンを挟んで指定すると、逆にネットワークアドレスやプレフィックスが分かります。

# ipcount 192.168.0.0 - 192.168.0.255
192.168.0/24 192.168.0.0 - 192.168.0.255 [256]

一つのサブネットで表現できない場合、複数のネットワークに分けて表示されます。

# ipcount 192.168.0.200 - 192.168.0.255
192.168.0.200/29 192.168.0.200 - 192.168.0.207 [8]
192.168.0.208/28 192.168.0.208 - 192.168.0.223 [16]
192.168.0.224/27 192.168.0.224 - 192.168.0.255 [32]
192.168.0.200/29,/28,/27 192.168.0.200 - 192.168.0.255 [56]

ちなみに、プレフィックスの代わりにサブネットマスク(255.255.255.0)は指定できないようです。サブネットマスクへの読み替えには、iptab コマンドを使いましょう。

# iptab
+----------------------------------------------+
| addrs   bits   pref   class  mask            |
+----------------------------------------------+
|     1      0    /32          255.255.255.255 |
|     2      1    /31          255.255.255.254 |
|     4      2    /30          255.255.255.252 |
|     8      3    /29          255.255.255.248 |
|    16      4    /28          255.255.255.240 |
|    32      5    /27          255.255.255.224 |
|    64      6    /26          255.255.255.192 |
|   128      7    /25          255.255.255.128 |
|   256      8    /24      1C  255.255.255.0   |
|   512      9    /23      2C  255.255.254.0   |
|    1K     10    /22      4C  255.255.252.0   |
|    2K     11    /21      8C  255.255.248.0   |
|    4K     12    /20     16C  255.255.240.0   |
|    8K     13    /19     32C  255.255.224.0   |
|   16K     14    /18     64C  255.255.192.0   |
|   32K     15    /17    128C  255.255.128.0   |
|   64K     16    /16      1B  255.255.0.0     |
|  128K     17    /15      2B  255.254.0.0     |
|  256K     18    /14      4B  255.252.0.0     |
|  512K     19    /13      8B  255.248.0.0     |
|    1M     20    /12     16B  255.240.0.0     |
|    2M     21    /11     32B  255.224.0.0     |
|    4M     22    /10     64B  255.192.0.0     |
|    8M     23     /9    128B  255.128.0.0     |
|   16M     24     /8      1A  255.0.0.0       |
|   32M     25     /7      2A  254.0.0.0       |
|   64M     26     /6      4A  252.0.0.0       |
|  128M     27     /5      8A  248.0.0.0       |
|  256M     28     /4     16A  240.0.0.0       |
|  512M     29     /3     32A  224.0.0.0       |
| 1024M     30     /2     64A  192.0.0.0       |
| 2048M     31     /1    128A  128.0.0.0       |
| 4096M     32     /0    256A  0.0.0.0         |
+----------------------------------------------+

ipcalc , sipcalc

ipcalcでIPを指定すると、そのIPのクラスとプライベートアドレスなのかどうかを表示します。--all-info オプションを付けると、さらにIPを保有している国や、大まかな位置情報なども表示されます。

sipcalcの場合、IPを指定すると主にIPの別進数(10,16表記が表示される。--all オプションを付けると、2進数表記も表示されるほか、IPのクラス等の情報が表示される。

ipcalcでIPを指定

# ipcalc 8.8.8.8
Address: 8.8.8.8
Address space: Internet
Address class: Class A











ipcalc に--all-info オプションを付与

# ipcalc 8.8.8.8 --all-info
Address: 8.8.8.8
Reverse DNS: 8.8.8.8.in-addr.arpa.
Address space: Internet
Address class: Class A

Country code: US
Country: United States
Coordinates: 37.751000,-97.822000

sipcalcでIPを指定

# sipcalc 8.8.8.8
-[ipv4 : 8.8.8.8] - 0
[CIDR]
Host address - 8.8.8.8
Host address (decimal) - 134744072
Host address (hex) - 8080808
Network address - 8.8.8.8
Network mask - 255.255.255.255
Network mask (bits) - 32
Network mask (hex) - FFFFFFFF
Broadcast address - 8.8.8.8
Cisco wildcard - 0.0.0.0
Addresses in network - 1
Network range - 8.8.8.8 - 8.8.8.8


sipcalc--allオプションを付与

# sipcalc 8.8.8.8 --all
-[ipv4 : 8.8.8.8] - 0
[Classful]
Host address - 8.8.8.8
Host address (decimal) - 134744072
Host address (hex) - 8080808
Network address - 8.0.0.0
Network class - A
Network mask - 255.0.0.0
Network mask (hex) - FF000000
Broadcast address - 8.255.255.255
[CIDR]
Host address - 8.8.8.8
Host address (decimal) - 134744072
Host address (hex) - 8080808
Network address - 8.8.8.8
Network mask - 255.255.255.255
Network mask (bits) - 32
Network mask (hex) - FFFFFFFF
Broadcast address - 8.8.8.8
Cisco wildcard - 0.0.0.0
Addresses in network - 1
Network range - 8.8.8.8 - 8.8.8.8
[Classful bitmaps]
Network address - 00001000.00000000.00000000.00000000
Network mask - 11111111.00000000.00000000.00000000
[CIDR bitmaps]
Host address - 00001000.00001000.00001000.00001000
Network address - 00001000.00001000.00001000.00001000
Network mask - 11111111.11111111.11111111.11111111
Broadcast address - 00001000.00001000.00001000.00001000
Cisco wildcard - 00000000.00000000.00000000.00000000
Network range - 00001000.00001000.00001000.00001000 -
00001000.00001000.00001000.00001000
[Networks]
Network - 8.8.8.0 - 8.8.8.0
Network - 8.8.8.1 - 8.8.8.1
Network - 8.8.8.2 - 8.8.8.2
Network - 8.8.8.3 - 8.8.8.3
~省略~

プレフィックスを付けると以下の表示になります。青字がプレフィックスを付けない時との差分です。両コマンドとも、IPの範囲や数が表示されるようになります。

ipcalcでIPをプレフィックス付きで指定

# ipcalc 8.8.8.8/24
Address: 8.8.8.8
Network: 8.8.8.0/24
Netmask: 255.255.255.0 = 24
Broadcast: 8.8.8.255

Address space: Internet
Address class: Class A
HostMin: 8.8.8.1
HostMax: 8.8.8.254
Hosts/Net: 254




ipcalcはサブネットマスクを指定することもできます。

※ ipcalc 8.8.8.8 255.255.255.0
(表示は同じ)

sipcalcでIPをプレフィックス付きで指定

# sipcalc 8.8.8.8/24
-[ipv4 : 8.8.8.8/24] - 0
[CIDR]
Host address - 8.8.8.8
Host address (decimal) - 134744072
Host address (hex) - 8080808
Network address - 8.8.8.0
Network mask - 255.255.255.0
Network mask (bits) - 24
Network mask (hex) - FFFFFF00
Broadcast address - 8.8.8.255
Cisco wildcard - 0.0.0.255
Addresses in network - 256
Network range - 8.8.8.0 - 8.8.8.255
Usable range - 8.8.8.1 - 8.8.8.254

sipcalcもサブネットマスクを指定することもできます。

# sipcalc 8.8.8.8 255.255.255.0
(表示は同じ)

ipcalcはDNSへの問い合わせもできます。IPからホスト名(dig -x コマンド相当)を確認します。なお、sipcalc には同様の機能は無いようです。

ipcalcでホスト名を確認

# ipcalc -h 8.8.8.8
HOSTNAME=dns.google

他にも、ipcalcでは、IPの表記が間違ってないか確認したり、サブネットマスクからプレフィックスの値だけを表示したりすることもできます。

ipcalcでIP表記やプレフィックス付きのIPが有効な表記か確認

# ipcalc -c 8.8.8.8
# echo $?
0   ※ 有効なアドレスなのでコマンドの戻り値が0

# ipcalc -c 8.8.8.300
ipcalc: bad IPv4 address: 8.8.8.300
# echo $?
1   ※ 無効なアドレスなのでコマンドの戻り値が1

# ipcalc -c 8.8.8.8/24
# echo $?
0   ※ 有効なアドレスなのでコマンドの戻り値が0

# ipcalc -c 8.8.8.8/99
ipcalc: bad IPv4 prefix: 99
# echo $?
1   ※ 無効なアドレスなのでコマンドの戻り値が1

ipcalcでサブネットのプレフィックス値を確認

# ipcalc --prefix 8.8.8.8 255.255.255.0
PREFIX=24

Dockerコンテナイメージファイル(tar)からファイル抽出

コンテナのイメージファイル(tar)から、Dockerを使わずにファイルを抽出する方法の紹介です。

まずは、以下のpythonスクリプトを書きます。
※ 1行目の #!/usr/bin/python3 は自身のpython3のパスに適宜読み替えてください。

docker-image-extract.py

#!/usr/bin/python3

import tarfile
import json
import os
import sys

image_path = sys.argv[1]
extracted_path = sys.argv[2]

image = tarfile.open(image_path)
manifest = json.loads(image.extractfile('manifest.json').read())

for layer in manifest[0]['Layers']:
    print('Found layer: %s' % layer)
    layer_tar = tarfile.open(fileobj=image.extractfile(layer))

    for tarinfo in layer_tar:
        print('  ... %s' % tarinfo.name)
        if tarinfo.isdev():
            print('  --> skip device files')
            continue

        dest = os.path.join(extracted_path, tarinfo.name)
        if not tarinfo.isdir() and os.path.exists(dest):
            print('  --> remove old version of file')
            os.unlink(dest)

        layer_tar.extract(tarinfo, path=extracted_path)

busyboxのコンテナイメージファイル busybox.tar の中身を busybox-image-files ディレクトリ名配下に抽出します。以下のようにコンテナ内の全ファイルが抽出されます。

# ./docker-image-extract.py busybox.tar busybox-image-files
Found layer: df8698476c65c2ee7ca0e9dbc2b1c8b1c91bce555819a9aaab724ac64241ba67.tar.gz
… bin
… bin/[
… bin/[[
… bin/acpid
… bin/add-shell
… bin/addgroup
… bin/adduser
… bin/adjtimex
… bin/ar
… bin/arch
~省略~
… var
… var/spool
… var/spool/mail
… var/www

このような感じでファイルが抽出されました。

# ls -l busybox-image-files/
total 40
drwxr-xr-x 2 root root 12288 Sep 25 22:31 bin
drwxr-xr-x 2 root root 4096 Sep 9 03:09 dev
drwxr-xr-x 3 root root 4096 Sep 25 22:31 etc
drwxr-xr-x 2 nobody nobody 4096 Sep 9 03:09 home
drwx------ 2 root root 4096 Sep 9 03:09 root
drwxrwxrwt 2 root root 4096 Sep 9 03:09 tmp
drwxr-xr-x 3 root root 4096 Sep 25 22:31 usr
drwxr-xr-x 4 root root 4096 Sep 25 22:31 var

参考 : https://www.madebymikal.com/quick-hack-extracting-the-contents-of-a-docker-image-to-disk/

craneコマンドでDockerイメージをダウンロード・アップロード

以前、Dockerのコンテナイメージダウンロードに graboid というツールを紹介したのですが、 今回はアップロード (docker push相当) もできるgoogleが開発しているツール crane を紹介します。

インストール

craneはGO製のコマンドラインツールで、go-containerregistry というプロジェクトの一部です。craneコマンド以外にもgcraneやk8schainといったコマンドが提供されています。今回は、tar.gz ファイルダウンロード後、craneファイルだけを取り出して、/user/local/bin に配置します。
※ Windows版は提供されていないので、今回はLinux環境が前提です。

# curl -L https://github.com/google/go-containerregistry/releases/download/v0.1.3/go-containerregistry_Linux_x86_64.tar.gz -o /tmp/go-containerregistry.tar.gz
# tar zxvf /tmp/go-containerregistry.tar.gz -O crane > /usr/local/bin/crane
# chmod 755 /usr/local/bin/crane
# rm -f /tmp/go-containerregistry.tar.gz

コンテナイメージのダウンロード (pull)

ダウンロード(pull)は、コンテナイメージのURLと保存先ファイル名(tar)を指定するだけです。DockerHub上のbusyboxコンテナをダウンロードしてみます。DockerHubにログインしてないため、No matching credentials were found というワーニングがでますが、無視して構いません。

# crane pull busybox busybox.tar
2020/09/25 08:01:42 No matching credentials were found, falling back on anonymous
# ls
busybox.tar

コンテナイメージのアップロード (push)

アップロード(push)も、認証が特にかかっていないレジストリの場合は、以下のようにtarファイル名とアップロード先URL(ここではmyregistry:5000というサーバを想定)を指定します。pullと引数が逆なので注意してください。

# crane push busybox.tar myregistry:5000/busybox:latest

認証は cran auth login サーバURL -u ユーザ名 -p パスワード コマンドできます。なお、パスワードをコマンドラインで対話的に入力する機能はないようです。パスワードを直接指定してDockerHubにログインしてみます。

# crane auth login docker.io -u myusername -p mypassword

コマンドラインに直接パスワードを入力したくない場合、-pオプションの代わりに--password-stdinオプションを使って、標準入力からパスワードを受け取ることができます。pass.txt というテキストファイルにパスワードを書いて、以下のようにログインできます。

# cat pass.txt | crane auth login docker.io -u myusername --password-stdin

なお、ログインした場合 ~/.docker/config.json に認証情報が保存されます。つまり、Dockerがインストールされている環境で、docker login を実行している場合、新たに crane コマンドでログインする必要はありません。

ログイン後のpushは最初に紹介した方法と同じです。DockerHub だとpush先のパスにユーザ名が必要なので、以下のようなコマンドでpushできます。

# crane push busybox.tar myusername/busybox:latest

Dockerで日本語入力対応Linuxデスクトップ環境

Dockerを使うと様々なアプリを簡単にhttps://github.com/Rosyuku/ubuntu-rdp起動できますが、基本的にCUIでの操作やWeb経由でのアクセスがメインだと思います。しかし、Linuxデスクトップ環境をコンテナ使って構築できると便利だなと思い探してみました。

調査に使ったコンテナ実行環境は、Docker 19.03 on CentOS 7で、アクセスに使った環境は Chrome on Windows 10です。

docker-ubuntu-vnc-desktop ⇒ 日本語未対応

まずはじめに試したのが、docker-ubuntu-vnc-desktop というコンテナ。名前にはVNCと入ってますが、VNCで接続するものではなくブラウザから接続します。

Quick Startに書かれている通り、以下のコマンドで起動しました。-pでマッピングするポートは適宜読み替えてください。本記事では基本的に8080ポートを使います。

# docker run -p 8080:80 -v /dev/shm:/dev/shm dorowu/ubuntu-desktop-lxde-vnc

ブラウザから、http://ホストのIP:8080ポートにアクセスすると以下のようにデスクトップが表示されました。

デフォルトで、ターミナルやブラウザ(Firefox, Chrome)が入っていましたが、Chromeは私の環境ではなぜか起動しませんでした。

これを最初に起動して思ったのが、日本語入力環境がないのが不便で、コンテナ起動する度に日本語設定するのは面倒だなということです。ということで、以降では日本語に対応した Linuxデスクトップ環境を探してまとめてみました。

docker-xrdp ⇒ 画面真っ黒で表示されず

次に試したのが、docker-xrdp というコンテナです。Qiita で「Dockerで日本語入力可能なubuntu 20.04イメージを作りました (xrdp)」という記事で紹介されている通り、デフォルトで日本語入力可能を謳っています。xrdp と書かれているとおり、接続にはリモートデスクトップを使います。

Qiitaの記事によると、--shm-size オプション使わないとFirefoxがクラッシュするらしいので、これを付与して起動します。パスワードは指定しないと自動生成されるらしいですが、ここでは「hogehoge」を指定しました。

# docker run -p 8080:3389 --shm-size=1g -e PASSWD=hogehoge tukiyo3/xrdp:core

リモートデスクトップからサーバの8080ポートに接続すると、以下のxrdpのログイン画面が現れました。

デフォルトのユーザ名は、「focal」で、パスワードには起動時に指定したhogehogeを入力するとログインは成功しマウスカーソルが表示されます。画面上で右クリックすると以下のようなメニューが出てくるのですが、画面全体がなぜか真っ黒でタスクバーなどが表示されず、まともなデスクトップが表示されませんでした・・・

ubuntu-desktop-jp ⇒ 日本語入力できず

次が、「日本人向けのUbuntuデスクトップ環境」を謳っている ubuntu-desktop-jp です。こちらは最初に紹介したdocker-ubuntu-vnc-desktopのように、ブラウザ経由で使うコンテナのようです。

GitHubに書かれているコマンドで起動してみます。

# docker run --rm -p 8080:8080 uphy/ubuntu-desktop-jp:18.04

ブラウザから、8080ポートにアクセスすると以下の画面が表示されました。

デフォルトの日本語入力ONのキーは、「Super + Space」になっていますが、Windows環境で Windowsキー + Space を押すと、Windowsの日本語入力選択画面が表示されてしまい、Linuxデスクトップ側の日本語入力をONにすることができませんでした。よって、IBus Preferences の設定を開き、<Super>space を <Shift>space に変更してみました。

この状態で、ターミナルを開き Shift + Spaceを押すと、日本語入力切替画面が出てくるようになりましたが、なぜか日本語入力できません・・・

右上のアイコンから「ひらがな」を選んでもやっぱり無理。ちなみにブラウザも開きませんでした。

openbox-mozc-docker ⇒ 日本語入力できず

次に試したのが、openbox-mozc-docker です。日本語入力ができるシンプルなデスクトップ環境のようで、接続はVNCです。

ビルド済みのコンテナがないので、Dockerfileからビルドする必要があります。(数分要します)

# git clone https://github.com/hiroshi-nishiura/openbox-mozc-docker.git
# cd openbox-mozc-docker/
# docker build -t openbox-mozc-docker .

ビルドが完了したら、起動します。

# docker run --rm -it -p 8080:5900 openbox-mozc-docker xvnc

VNC Viewerを使って8080ポートに接続すると、背景が真っ黒な超シンプルな画面が表示されました。(画面下にタスクバーは表示されています)

デフォルトの日本語入力はCtrl + Spaceになっていますので、ブラウザを起動してCtrl + Spaceを押してみましたが、反応がありません。どうやら、Input Methodが設定されていないようです・・・。GitHubに書いてるようにEmacs以外については、日本語入力できるように設定されていないのかもしれません。

yama07/docker-ubuntu-lxde ⇒ 日本語入力可。シンプル。起動時エラーあり

次は、docker-ubuntu-lxde です。Ubuntu + LXDEをベースの日本語入力対応を謳ってます。接続にはリモートデスクトップを使います

まずは、GitHubのREADMEに何も書かれてないので、DockerHub のドキュメントを見ながら起動してみます。「rootユーザとして起動した場合は、日本語入力(mozc)が利用できません。」とあるので、-u には別ユーザIDとグループIDを指定しています。--privileged も付けておいた方がよいとのことなので、つけてます。

# docker run --privileged --rm -it -p 8080:3389  -u 1000:1000  -e USER=test -e PASSWD=hogehoge yama07/docker-ubuntu-lxde:ubuntu18.04_ja

リモートデスクトップで、8080ポートに接続すると、先程と同じくxrdpの見慣れたログイン画面が出てきます。

起動時に指定した、ユーザ test, パスワード hogehoge でログインすると、DockerHubのドキュメントみたいな背景ではなく、真っ黒なシンプルなLXDEの画面が出てきました。

しかし、ログイン時に以下のエラー画面が出て、コンテナのログにも以下のエラーが出力されました。

xrdp-sesman[42]: pam_systemd(xrdp-sesman:session): Failed to create session: Input/output error

デフォルトの日本語入力切替が Super + Space になっているのですが、ONにならなかったので、ubuntu-desktop-jp の時と同じように、IBus Preferencesの設定画面を開いて、Shift + Space に変更しました。

この状態で、ターミナルを起動して、Shift + Space を押すと、日本語切替の画面が以下のように出てきましたが、「あ」を選択しても日本語入力できません。

しかし、画面右下のアイコンから、入力モードを手動で「ひらがな」に変更すると、無事日本語入力ができました。

ちなみに、ブラウザ(Firefox)も起動できました。

rosyuku/ubuntu-rdp ⇒ 日本語入力可。シンプル

ubuntu-rdp は、リモートデスクトップとSSH接続ができる、日本語入力対応のコンテナと謳われています。

起動してみます。

# docker run --rm -it -p 8080:3389 -p 10022:22 --shm-size=256m rosyuku/ubuntu-rdp:0.1.2

また、xrdp のログイン画面が出てくるので、デフォルトのIDとパスワード my-ubuntu / my-Password でログインします。

画面は、ubuntu-desktop-jp と同じですが、デスクトップのアイコンは日本語化されていませんでした。

上と同じく、IBus Preferencesの設定画面を開いて、Shift + Space に変更します。

ターミナルを開いて、Shift + Space 入力をONにします。

yama07/docker-ubuntu-lxde 同様に、ONにしただけでは日本語が入力できなかったので、画面右上から「ひらがな」を選択すると、無事入力できました。

ちなみにブラウザ(Firefox)も起動でき、日本語入力できました。

docker-centos-xfce-ja ⇒ 日本語入力可。CentOSベース。

最後が、docker-centos-xfce-ja です。今まで紹介してきたコンテナは全てUbuntuベースでしたが、こちらはCentOSベースで、ブラウザ経由でもリモートデスクトップでもアクセスできるようです。さらに、SSHやブラウザ経由でターミナルにアクセスできたり、ファイル管理(アップロード・ダウンロードも可)もできたり、ブラウザ版VSCodeも使えたり、デフォルトでHTTPSで暗号化できたりと、かなり機能盛りだくさんです。

起動してみます。ポート8080がWebアクセス(https)用、22がssh用、3389がリモートデスクトップ用になっているようなので、それぞれを-pでマッピングしています。

# docker run -d -p 8080:8080 -p 10022:22 -p 8081:3389 -e PASSWORD=hogehoge --name centos-xfce-ja --shm-size=2g tmatsuo/centos-xfce-ja:1.2

※ 機能豊富な分イメージがでかいです。

まずは、ブラウザでアクセスしてみます。機能盛りだくさんのため、機能毎にアクセスするパスが決まっているようで、Linuxデスクトップにアクセスしたい場合、
    https://サーバIP:8080/desktop/
にアクセスします。オレオレ証明書のため証明書エラーが出ますが、エラーを無視して接続すると、ベーシック認証画面がでてきます。

ドキュメントによると、Nginxがフロント(リバースProxy)にいて、PAMを使って認証しているようです。上記ベーシック認証画面で、IDにroot, パスワードは起動時に指定したパスワード hogehoge を入力すると、以下の画面が表示されました。

日本語入力ONは、Shift + Spaceに設定されていると書かれているので、ターミナルを起動して、Shift + Spaceを押すとONにできました。

日本語入力もデフォルトの設定で問題なくできます。今までのコンテナ中で一番手軽です。

リモートデスクトップでも繋いでみます。起動時に指定した8081ポートに繋いでみると、先程ブラウザで起動したターミナルが見えます。ブラウザとリモートデスクトップで同じ画面が表示されるようです。

ついでに他の機能にもアクセスしてみました。ブラウザから
    https://サーバIP:8080/term/
にアクセスすると、ログインプロンプトが出てき、先程のIDとパスワードでログインできました。

ブラウザから
    https://サーバIP:8080/file/
にアクセスすると、以下のようにファイルブラウザが表示されました。操作端末との間でファイルやりとりするのも簡単そうです。

ブラウザから
    https://サーバIP:8080/code/
にアクセスすると、以下のようにVS Codeの画面が表示されました。ここまでお膳立てされていると、ちょっとした開発ならすぐにでも開始できそうです。

まとめ

いろいろなコンテナを起動してみましたが、日本語対応を謳っていても実際はうまく起動できなかったり日本語入力できなかったりするものが多い印象です。今回はあまり深くは触っていませんが、

シンプルなUbuntuベースのLinuxデスクトップ ⇒ rosyuku/ubuntu-rdp

高機能なCentOSベースのLinuxデスクトップ ⇒ docker-centos-xfce-ja

の二択かなと思いました。

legoコマンドでLet's Encrypt

Let's EncryptのTLS(https)証明書を取得するのにcertbotというツール(コマンド)がよく使われますが、今回は lego というツールを紹介します。

GO製ツールで実行ファイルはシングルバイナリファイルのため、インストールも簡単です。GitHubのリリースページから対象のOSやアーキテクチャのtar.gzファイルをダウンロードし、展開して出てくるlegoファイルを、Linuxなら/usr/local/bin/辺り(PATHが通ったディレクトリ)に放り込むだけです。

すでにWebサーバが構築されており、そのサーバにドメインが割り当てられている場合、以下のようなコマンドで証明書を取得できます。

# lego --accept-tos --http --http.webroot /var/www/html/ --domains example.com --path /etc/lego/ --email [email protected] run

/var/www/html が、Webサーバのドキュメントルートです。example.com がサーバのドメイン名で、[email protected] がメールアドレスです。取得した証明書は、--path で指定した/etc/legoに保存されます。各引数の値は、適宜環境にあわせて修正してください。

実行すると、上記で指定した/var/www/html ディレクトリに、.well-known というディレクトリが作成され、Let's Encrypt がドメインの所有者有無を確認するためのファイルが配置されます。

証明書保存先の/etc/lego/ には、certificates というディレクトリが作成され、ドメイン名が付与されたファイルが4つ作成されます。

# ls /etc/lego/certificates/
/etc/lego/certificates/example.com.crt
/etc/lego/certificates/example.com.json
/etc/lego/certificates/example.com.crt
/etc/lego/certificates/example.com.key

あとは、自身のWebサーバで上記証明書を指定すれば、Let's Encryptの証明書が使えるようになります。

Let's Encryptの証明書は3ヶ月で期限が切れるため、定期的に更新が必要になります。証明書の更新は、runの代わりにrenewを使います。

# lego --accept-tos --http --http.webroot /var/www/html --domains example.com --path /etc/lego/ --email [email protected] renew --days 30 --renew-hook /usr/local/bin/restart-server.sh

更新を頻繁に実行すると制限にひっかかってしまいますので、上記では--days 30を指定して、証明書の期限が30日を切った場合に更新処理が実行されるように設定しています。--renew-hook では、更新後に実行するスクリプトを指定します。ここでは/usr/local/bin/restart-server.sh(予め作成)を指定し、Webサーバを再起動しています。この処理を1ヶ月に1回ぐらいcron等で実行してあげれば、自動で証明書の更新も可能です。

コンテナを使ってWebサイトの脆弱性スキャン

とりあえず、サイトの脆弱性調査のためにフルスキャンしたい場合、Dockerがインストールされている環境で以下のコマンド叩けばできます。
※ 他人のサイトに向けて以下のスキャンを試すと、不正アクセスで訴えられる可能性があるため絶対に行わないでください。

# docker run -t owasp/zap2docker-stable zap-full-scan.py -t https://{スキャンしたいURL} 2>&1 | tee -a scanlog.txt

なお、フルスキャンはかなり時間がかかります。(数時間ぐらい?)
結果は tee を用いているので、画面に表示されつつ scanlog.txt にも保存されます。

Podmanでコンテナのログをjournaldへ転送

RHEL8 (CentOS8)からは、Dockerが同梱されておらず、代わりにPodmanが提供されています。PodmanはDockerのようにデーモンがおらず、機能もシンプルです。ここでは、Podmanで起動したコンテナのログの保存方法について紹介します。

podman run コマンドで起動したコンテナのログは、通常はpodmanの管理領域に保存され、コンテナを削除すると削除されてしまいます。これだと、実際の運用では古いログが参照できなくて困ってしまいます。これを避けるには、ログドライバーをコンテナ起動時に指定します。

ここでは、CentOS 8のPodmanを前提に書きますが、以下のように、--log-driver journald というオプションを付けると、コンテナのログがjournaldに出力されるようになります。

# podman run -d --log-driver journald nginx

CentOS 8では、journald に出力されたログは、デフォルトでrsyslogを経由して/var/log/messagesに保存されるため、これによりコンテナのログを永続化することができるようになります。Dockerだと、ログ設定をデフォルトの設定で変更できるようですが、Podmanではそのような設定ファイルがないようで、podman run 時に毎回付与する必要がありそうです。

なお、Dockerの場合、--name nginx のようなオプションを付けると、journaldのログのメタデータにCONTAINER_NAME=nginx といった情報が付与されるため、journalctl -o json コマンドで見るとどのコンテナのログか簡単に判別できますし、rsyslogのフィルタ設定によってコンテナ名でログファイルを分けることができるのですが、2020年9月現在のCentOS 8のpodman はこのメタデータが付与されませんでした。この不具合は、GitHubのこちらのIssueで修正されたようなので、そのうち正常に本メタデータも保存されるようになりそうです。

mod_security(OWASP) + Wordpressで「返答が正しい JSON レスポンスではありません」エラー発生

WAFにmod_securityを使い、ルールとしてOWASP を使用してWordpressを攻撃から守る場合、デフォルトのルールのまま使うと、Wordpressで記事保存する時に「返答が正しい JSON レスポンスではありません」というエラーが発生しました。これは、OWASPのルールID 949110 に引っかかってしまっているようで、WAFのログにも以下のような出力が見られ、記事保存時のアクセスがWAFによって怪しいアクセスと認識されたのが原因でした。

ModSecurity: Access denied with code 403 (phase 2). Matched 
"Operator `Ge' with parameter `5' against variable 
`TX:ANOMALY_SCORE' (Value: `10' ) [file "/~省略~/
REQUEST-949-BLOCKING-EVALUATION.conf"] [line "80"] 
[id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded 
(Total Score: 10)"]~省略~

これを回避するには、上記949110のルールを削除するのも手の一つですが、本当の攻撃が防げなくなる可能性もあり、あまり好ましくありません。

回避するには、OWASPの設定ファイル crs-setup.conf のWordpress向けの設定を有効にしましょう。

具体的には、上記ファイル内のルール ID : 900130 がデフォルトで以下のようにコメントアウトされた状態で書かれています。

#SecAction \
# "id:900130,\
#  phase:1,\
#  nolog,\
#  pass,\
#  t:none,\
#  setvar:tx.crs_exclusions_cpanel=1,\
#  setvar:tx.crs_exclusions_drupal=1,\
#  setvar:tx.crs_exclusions_dokuwiki=1,\
#  setvar:tx.crs_exclusions_nextcloud=1,\
#  setvar:tx.crs_exclusions_wordpress=1,\
#  setvar:tx.crs_exclusions_xenforo=1"

これを以下のように修正します。

SecAction \
 "id:900130,\
  phase:1,\
  nolog,\
  pass,\
  t:none,\
  setvar:tx.crs_exclusions_wordpress=1"

あとは、WAFで設定ファイルをリロードすれば、無事Wordpressで記事保存ができるようになりました。

CentOS 7 → CentOS 8 (8.2)へのアップグレード

このあたりのブログで、CentOS 7 から CentOS 8 へのアップグレード方法が紹介されていますが、すでにブログ公開から1年たち、CentOSも8.2になってしまったためか、紹介されていた手順ではアップグレードに失敗してしまいました。以下に2020/7時点で成功した手順をメモとして残しておきます。

# yum -y update;
yum -y install epel-release;
yum -y install yum-utils;
yum -y install rpmconf;
rpmconf -a;

package-cleanup --leaves;
package-cleanup --orphans;
yum -y install dnf;
dnf -y remove yum yum-metadata-parser;
rm -Rf /etc/yum;
dnf upgrade -y;

dnf -y upgrade http://mirror.bytemark.co.uk/centos/8.2.2004/BaseOS/x86_64/os/Packages/centos-release-8.2-2.2004.0.1.el8.x86_64.rpm http://mirror.bytemark.co.uk/centos/8.2.2004/BaseOS/x86_64/os/Packages/centos-gpg-keys-8.2-2.2004.0.1.el8.noarch.rpm http://mirror.bytemark.co.uk/centos/8.2.2004/BaseOS/x86_64/os/Packages/centos-repos-8.2-2.2004.0.1.el8.x86_64.rpm
dnf -y upgrade https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm;

dnf clean all;
rpm -e `rpm -q kernel`;
rpm -e --nodeps sysvinit-tools;
rpm -e `rpm -q kernel-tools`;
rpm -e `rpm -q kernel-tools-libs`;
rpm -e `rpm -q kexec-tools`;
dnf -y remove python36-rpmconf;
dnf -y --releasever=8 --allowerasing --setopt=deltarpm=false distro-sync;
dnf -y install kernel-core;
dnf -y install kexec-tools;
dnf -y install python3-rpmconf;
dnf -y groupupdate "Core" "Minimal Install" --allowerasing;

Pixel 3a(Android 9)の電池消費がひどい

ほぼ触っていないPixel 3aの電池消費が以下のようにひどく困ってました。
※ 最後にちょっと充電したので残量が上がっている箇所がありますが気にしないでください。

ネットで情報をいろいろ探していたところ、どうやら固定IPを使ってWifiに繋ぐと電池消費がひどくなるとの報告をGoogleのサポートページで見つけました。当方、諸事情により固定IPを使っていたのですが、試しにDHCPに設定を変更したところ、見事に電池消費が改善しました!

Kubernetesのコンパイル

昨今、OSSを製品からコンパイルして使うことは少なくなってきましたが、Kubernetesのソースを改変したりデバッグしたりしてみたかったので、コンパイルしてみました。

コンパイルって結構面倒なイメージですが、KubernetesのコンパイルはDockerを利用してコンパイルするためのスクリプトが用意されています。つまりDockerが使える環境なら、スクリプトを実行するだけです。
※ Dockerのインストールはここでは割愛します。

まずは、ソースコードをcloneし、ディレクトリを移動します。

# git clone https://github.com/kubernetes/kubernetes.git
# cd kubernetes

コンパイルします。引数にmakeだけを指定するとLinuxのバイナリを生成してくれます。
※ コンパイル環境まで数分かかりました。

# ./build/run.sh make
~ 略 ~
Coverage is disabled.
+++ [1029 21:59:25] Placing binaries
+++ [1029 22:00:00] Syncing out of container
+++ [1029 22:00:00] Stopping any currently running rsyncd container
+++ [1029 22:00:00] Starting rsyncd container
+++ [1029 22:00:01] Running rsync
+++ [1029 22:00:25] Stopping any currently running rsyncd container

バイナリは_outputディレクトリに出力されました。

# ls _output/dockerized/bin/linux/amd64/
apiextensions-apiserver  genswaggertypedocs       kube-scheduler
conversion-gen           genyaml                  kubeadm
deepcopy-gen             ginkgo                   kubectl
defaulter-gen            go-bindata               kubelet
e2e.test                 go-runner                kubemark
e2e_node.test            go2make                  linkcheck
gendocs                  kube-apiserver           mounter
genkubedocs              kube-controller-manager  openapi-gen
genman                   kube-proxy

非常に簡単ですね。

Androidのアプリ内課金の支払いアカウントを変更する

Androidのスマホに複数のGoogleアカウントを登録し、アプリをインストールしている場合、アプリ内課金はどのアカウントで支払われるのでしょうか?

支払い時にアカウントを変更することはできず、ネットを見てるとスマホに最初に登録したアカウントが使われるという情報があったのですが、残念ながら変更できませんでした。それで自分でいろいろ試した結果、結論としてはGoogle Playからアプリダウンロードした時のアカウントのようです。これはアプリを削除した場合に、Google Playのでアカウントを選択後、"マイアプリ&ゲーム"の"ライブラリ"に表示されるものになります。

では、すでに他のアカウントでダウンロードしてしまったアプリのアカウントを変更するにはどうしたらよういでしょうか。

まずやってみたことは、単純にアプリをスマホから削除後、ライブラリかれも削除し、アカウント変更しての再ダウンロードです。 ※ 下記画像は削除イメージえあり、実際は News+ で試したわけではありません。

マイライブラリからの削除

アカウントの変更

しかしながら、アプリが旧アカウントと紐付いてしまっているのか、アプリダウンロード元のアカウントを変更することができませんでした。実際、アプリを削除すると旧アカウントのライブラリにまた表示されてしまいました。

よって、無理やりアカウントを変更する手段として、PCのブラウザ使用しました。 ※ スマホのブラウザでもできるかもしれませんが、未確認です。

手順としては、まずは再度アプリ削除し、ライブラリからも削除します。その後、PC上のブラウザからアカウント変更後のGoogleアカウントにログインし、Google Playにアクセスします。そこでインストールしたいアプリを探して、インストールをクリックすると、変更後のアカウントでスマホにアプリをリモートインストールできます。これで私は無事アプリ内課金のアカウントを変更することができました。

Windows10にssh-agentをインストール

WindowsのPowerShell向けのssh-agentをインストールしてみましたので、その時のメモです。2019/6月現在、最新版は v7.9.0.0p1-Beta が公開されているので、これを使います。

上記ページからOpenSSH-Win64.zipをダウロードし展開します。PowerShellのアイコンを右クリックし「その他→管理者として実行」で起動し、展開したフォルダに移動します。
※今回はc:\直下に展開したのでそこに移動しています。

PS C:\Windows\system32> cd C:\OpenSSH-Win64

デフォルトでは、Windowsサービスのインストーラ(PowerShellスクリプト)を実行する権限がないので、これを有効にします。
※ExecutionPolicyをRestrictedからRemoteSignedに変更します。

PS C:\OpenSSH-Win64> Get-ExecutionPolicy
Restricted

PS C:\OpenSSH-Win64> Set-ExecutionPolicy RemoteSigned
実行ポリシーの変更
実行ポリシーは、信頼されていないスクリプトからの保護に役立ちます。実行ポリシーを変更すると、about_Execution_Policies
のヘルプ トピック (https://go.microsoft.com/fwlink/?LinkID=135170)
で説明されているセキュリティ上の危険にさらされる可能性があります。実行ポリシーを変更しますか?
[Y] はい(Y) [A] すべて続行(A) [N] いいえ(N) [L] すべて無視(L) [S] 中断(S) [?] ヘルプ (既定値は "N"): y
PS C:\OpenSSH-Win64> .\install-sshd.ps1
警告: 発行元 OpenSSH のリソースが見つからなかったか、EventLog サービス アカウント
(NT SERVICE\EventLog) にアクセスできません。
[SC] SetServiceObjectSecurity SUCCESS
[SC] ChangeServiceConfig2 SUCCESS
[SC] ChangeServiceConfig2 SUCCESS
sshd and ssh-agent services successfully installed

PS C:\OpenSSH-Win64> Get-ExecutionPolicy
RemoteSigned

インストーラを実行します。

PS C:\app\OpenSSH-Win64> .\install-sshd.ps1
警告: 発行元 OpenSSH のリソースが見つからなかったか、EventLog サービス アカウント
(NT SERVICE\EventLog) にアクセスできません。
[SC] SetServiceObjectSecurity SUCCESS
[SC] ChangeServiceConfig2 SUCCESS
[SC] ChangeServiceConfig2 SUCCESS
sshd and ssh-agent services successfully installed

必要に応じてssh-agentをサービスを起動します
※ Windowsサービスのため、対象フォルダ(C:\OpenSSH-Win64)が暗号化されていると起動できないので注意。

PS C:\OpenSSH-Win64> Set-Service ssh-agent -StartupType Automatic
PS C:\OpenSSH-Win64> Start-Service ssh-agent
PS C:\OpenSSH-Win64> Get-Service ssh-agent
Status Name DisplayName
------ ---- -----------
Running ssh-agent OpenSSH Authentication Agent

以上で完了です。必要に応じて変更したセキュリティ設定を元に戻します。

PS C:\OpenSSH-Win64> Set-ExecutionPolicy Restricted
実行ポリシーの変更
実行ポリシーは、信頼されていないスクリプトからの保護に役立ちます。実行ポリシーを変更すると、about_Execution_Policies
のヘルプ トピック (https://go.microsoft.com/fwlink/?LinkID=135170)
で説明されているセキュリティ上の危険にさらされる可能性があります。実行ポリシーを変更しますか?
[Y] はい(Y) [A] すべて続行(A) [N] いいえ(N) [L] すべて無視(L) [S] 中断(S) [?] ヘルプ (既定値は "N"): y

参考
https://mimimopu.com/windows_powershell_ssh/
https://code.visualstudio.com/docs/remote/troubleshooting

expectでssh自動ログイン

sshで他のサーバーにログインする時に、毎回パスワード入力するのって面倒ですよね?

え? SSH鍵認証使えばパスワードなしでログインできるって?

その通りなんですが、ログイン先の環境を勝手にいじれなくてSSH公開鍵を置けない状況だったりすることもあるんです。

そういう場合の対処方法はいくつかあるんですが、今回はexpectコマンド使って自動化する方法を紹介します。

いたって簡単。実行環境にexpectコマンドが入っていれば以下のようなスクリプトを書くだけです。

#!/usr/bin/expect
set timeout 10
spawn ssh [email protected]
expect "password:"
send "hogehoge\n"
interact

上記の場合、ログインユーザがuser、サーバが192.168.0.1、パスワードがhogehogeの場合のスクリプトです。また、ログイン時に 「password:」というメッセージがサーバから送られてきたら、hogehoge + 改行 を送ってくれます。

ね、簡単でしょ。

スクリプトのデバッグしたいときは、「exp_internal 1」をスクリプトの最初で実行してあげればOKです。password: という文字にマッチしたかどうか等が確認できます。

このブログについて
プライバシーポリシー・お問い合わせ等
購読する(RSS)
記事検索
アーカイブ
カテゴリー
  • ライブドアブログ