Sophos Anti-Virus for Linux Free Edition が終わったので、今更 ClamAV をインストールした

こんにちは、masm11 です。

f:id:masm11:20210623014007p:plain

普段、家庭内サーバに Sophos Anti-Virus for Linux Free Edition をインストールして使ってました。 が、ある日突然、こんな通知が来ました。

Sophos Anti-Virus for Linux Free Edition の製品サポートは終了しています。 アップデートは引き続き入手できますが、後日終了される予定です。 詳細は、次のサイトを参照してください。 https://community.sophos.com/free-antivirus-tools-for-desktops/b/blog/posts/retirement-of-sophos-anti-virus-for-linux-free-edition

仕方なくアンインストールし、代わりに今更 ClamAV をインストールしたので、メモ代わりに残しておきます。

SAV をアンインストール

まず service を止めましょう。

様子を確認して、

[root@mike bin]# systemctl list-unit-files | grep sav
sav-protect.service                                                           enabled         disabled
sav-rms.service                                                               disabled        disabled
sav-update.service                                                            enabled         disabled

ひとつずつ止めていきます。

[root@mike bin]# systemctl stop sav-update
[root@mike bin]# systemctl disable sav-update
Removed /etc/systemd/system/multi-user.target.wants/sav-update.service.
[root@mike bin]# systemctl stop sav-protect
[root@mike bin]# systemctl disable sav-protect
Removed /etc/systemd/system/multi-user.target.wants/sav-protect.service.

もう一度確認します。

[root@mike bin]# systemctl list-unit-files | grep sav
sav-protect.service                                                           disabled        disabled
sav-rms.service                                                               disabled        disabled
sav-update.service                                                            disabled        disabled

全部 disable になってますね。では reboot します。

[root@mike bin]# reboot

残り作業であるファイルの削除は script に任せます。

[root@mike ~]# /opt/sophos-av/uninstall.sh 
Uninstalling Sophos Anti-Virus.
Sophos Anti-Virus has been uninstalled.

ClamAV のインストール

私は Arch Linux なので、↓こちらの資料を参考にしながら進めました。

https://wiki.archlinux.jp/index.php/ClamAV

まずインストールします。

mike:~ % sudo pacman -S clamav

freshclam を起動します。

mike:~ % sudo systemctl start clamav-freshclam.service 
mike:~ % sudo systemctl enable clamav-freshclam.service
Created symlink /etc/systemd/system/multi-user.target.wants/clamav-freshclam.service → /usr/lib/systemd/system/clamav-freshclam.service.

ここで、clamav-freshclam.service の中身を見るとわかるのですが、 /etc/cron.d/ で設定してあると、それは cron で定期的に起動することが 期待されるので、boot 時に起動しないようになっています。 私の場合はその設定はしてないので、boot 時に起動します。

で、ここでデータベースのダウンロードが始まります。 少し時間がかかるので、時々

mike:~ % sudo ls -l /var/lib/clamav/

を実行しながら、書き込みが収まるまで待ちましょう。

終わったら scan してみます。ウイルスのいそうなディレクトリ目がけて、えいやっと。

mike:~ % clamscan --recursive --infected --max-scansize=4000M /home/backup/luna-asus/masm/Mail/spam
/home/backup/luna-asus/masm/Mail/spam/6369: Img.Dropper.PhishingLure-6329856-0 FOUND
/home/backup/luna-asus/masm/Mail/spam/6759: Xls.Dropper.Generic-6595971-0 FOUND
/home/backup/luna-asus/masm/Mail/spam/6907: Xls.Dropper.Generic-6595971-0 FOUND
/home/backup/luna-asus/masm/Mail/spam/6370: Img.Dropper.PhishingLure-6329856-0 FOUND
/home/backup/luna-asus/masm/Mail/spam/6131: Xls.Dropper.Generic-6595971-0 FOUND

おぉ、ちゃんと検出してくれました。

では cron に仕掛けてしましょう。

mike:~% sudo crontab -e
0 2 1 * * /usr/bin/clamscan --recursive --infected --max-scansize=4000M --exclude-dir='^/sys|^/dev|^/proc' / | syslog -t clamscan

毎月1日の午前2時からスキャンを開始するようにしました。 この家庭内サーバはアクティブに使ってるサーバではないので、 この程度の頻度で定期的にスキャンするだけで十分です。 また、realtime scan とかやる気は全くありません。

ただ、本当はメール通知くらいはしたいんですけどね。 SAV の時はやってました (そのチャンネルを使ってサービス終了通知が来たわけです)。

まとめ

さすが ClamAV は簡単でいいですね。

スキャンにかかる時間にも注目したいです。 SAV の時はファイルシステム全体のチェックに丸2日程かかってました。 毎月3日くらいになると通知メールが来てたわけですね。 ClamAV でどのくらいかかるのでしょうね。

インゲージではエンジニアを募集しています。以下のページからお願いします!

https://ingage.co.jp/recruit/

ChatOps: SlackからLambdaに連携してみる(1)

id:kizashi1122 です。

最近、ChatOps ではないですが、ふと Slack から Lambda に連携し、AWS 内でゴニョゴニョしたいなと思い、下記のように連携をしたのですが、案外ネット上に情報がなく色々苦労したので、ここでまとめておこうかと思います。

f:id:ingage:20210620201734p:plain

目標

ここでは Slack に echoapp というアプリを作り、

@echoapp Hello!

と Slack に投稿すると、

Hello!

と同じ内容を返すアプリを作ってみましょう。 この「同じ内容を返す」という部分をAWS内のAPIを呼び出したり、外部の API を呼び出すなどすると色々と夢が広がると思います。

おおまかな手順

  1. Slack App を作成する
  2. Lambda を作成する
  3. API Gateway を作成する
  4. ここで発行した URL を Slack App に設定する

次回、「1. Slack App を作成する」をします。

お楽しみに。

続きはこちら。

ChatOps: SlackからLambdaに連携してみる(2) - インゲージ開発者ブログ

# から始まるコミットメッセージは無視される

起こったこと

僕はコミットメッセージに #ISSUE_NUMBER#PR_NUMBER を積極的に入れる派閥の人間なので

git revert -m 1 xxxxxxxxx を行った時にコミットメッセージの編集で

"#PR_NUMBER をマージしたコミットをリバートした #PR_NUMBER_2 をマージしたコミットを再度リバート(三度目の正直)"

という頭の悪いメッセージを入れようとしていたんですが、保存してもなぜか反映されないので困りました。

Revert "Merge pull request #PR_NUMBER_2 from revert-ikima-su"
    
This reverts commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, reversing
changes made to yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.

#PR_NUMBER をマージしたコミットをリバートした #PR_NUMBER_2 をマージしたコミットを再度リバート(三度目の正直)

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Fri Jun 11 10:51:42 2021 +0900
#
.
.
.

:wq
$ git show
commit zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz (HEAD -> sandomeno-shojiki)
Author: shutooike <shutofootball@icloud.com>
Date:   Fri Jun 11 10:51:42 2021 +0900

    Revert "Merge pull request #PR_NUMBER_2 from revert-ikima-su"
    
    This reverts commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, reversing
    changes made to yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.

diff --git ・・・・

文章がややこしすぎて vim が理解できない・・・?

解決

Revert "Merge pull request #PR_NUMBER_2 from revert-ikima-su"
    
This reverts commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, reversing
changes made to yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.

#PR_NUMBER をマージしたコミットをリバートした #PR_NUMBER_2 をマージしたコミットを再度リバート(三度目の正直)

# Please enter the commit message for your changes. Lines starting 
# with '#' will be ignored, and an empty message aborts the commit. 
#
# Date:      Fri Jun 11 10:51:42 2021 +0900
#
.
.
.

:wq

先ほどの vim の画面をもう一度よく読むと、

Lines starting with '#' will be ignored

書いてました。なるほど、vim は悪くなかったんですね。勉強になります📝

Revert "Merge pull request #PR_NUMBER_2 from revert-ikima-su"
    
This reverts commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, reversing
changes made to yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.

PR #PR_NUMBER をマージしたコミットをリバートした PR #PR_NUMBER_2 をマージしたコミットを再度リバート(三度目の正直)

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Fri Jun 11 10:51:42 2021 +0900
#
.
.
.

:wq

頭に「PR」をつけることで解決しました。

$ git show
commit zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz (HEAD -> sandomeno-shojiki)
Author: shutooike <shutofootball@icloud.com>
Date:   Fri Jun 11 10:51:42 2021 +0900

    Revert "Merge pull request #PR_NUMBER_2 from revert-ikima-su"
    
    This reverts commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, reversing
    changes made to yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.
    
    PR #PR_NUMBER をマージしたコミットをリバートした PR #PR_NUMBER_2 をマージしたコミットを再度リバート(三度目の正直)
   
diff --git ・・・・

いつもは git commit -m "コミットメッセージ #ISSUE_NUMBER" というスタイルだったのではじめてハマりました。

半年ぐらい後の自分がまたハマってそうなのでメモっておきます。

おわりに

弊社では全ての分野のエンジニアを絶賛大募集中です!ご興味あればぜひ下記リンクからお願いします!

ingage.co.jp

ではまた!

Linux デスクトップの環境変数、どこに設定してますか?

f:id:masm11:20210530233947j:plain

こんにちは、時々 Linux デスクトップの話を混ぜていきたい masm11 です。 今回は Linux デスクトップの環境変数をどこに設定するか、 というテーマで書きたいと思います。

環境変数の設定方法はいくつか用意されています。その紹介と、結局どこがいいの? という話です。

シェルの rc

環境変数と言えば真っ先に思いつくのがこれだと思います。 bash なら ~/.bashrc や ~/.bash_profile、私は zsh を使っているので ~/.zshenv になります。

export FOO=bar

という形式で設定しますね。

しかし、ここに書いても、効果があるのはシェルおよびそこから起動したプロセスのみですね。 デスクトップには効果がありません。 例えば gdm 等からログインすると、デスクトップから Emacs を起動しても、 ここに設定した環境変数は反映されていません。

~/.xprofile

「それならここじゃん!」と思う方、結構いらっしゃるのでは? ~/.xprofile です。

gdm からログインすると、デスクトップ起動前にこのファイルを読み込んで 実行してくれますね。

中身はシェルスクリプトですので、

export FOO=bar

と書いておけばいいです。また、シェルが実行するわけですから、

. $HOME/.zshenv

と書けば、設定箇所は一箇所で済みます。

しかしこれにも効果がない場合があります。

~/.xprofile はファイル名のとおり、X の場合にしか通用しません。 最近流行りの Wayland では読み込んでくれません。 私は Wayland なのです。

~/.pam_environment

さて、この辺からなんだか怪しくなってきます。 ~/.pam_environment というファイルに設定することもできます。

PAM をご存知でしょうか? Pluggable Authentication Module の略で、 認証まわりを引き受けているプログラムや設定ファイル群です。

設定ファイルは /usr/lib/pam.d/ や /etc/pam.d/ にあります。 例えば、私の /etc/pam.d/system-login には以下の行があります。

session    required   pam_env.so           user_readenv=1

この設定により、ログインセッションの初期化時に pam_env.so が実行されます。 pam_env.so に与えた user_readenv=1 によって、~/.pam_environment が 読み込まれます。

この ~/.pam_environment は以下のような形式です。

PATH    DEFAULT=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin

DEFAULT= だけでなく OVERRIDE= も書けるようなのですが、 詳細はまだ私も理解していないので省略します。

さすが PAM から読み込まれるだけあって、結構優秀です。いろんなパターンで使えます。

で、これの残念な点は、マニュアルに以下のように書いてあることです。

Due to problematic security this functionality is deprecated since
the 1.5.0 version and will be removed completely at some point in
the future.

なんと非推奨! 将来的には削除されるそうです。

homectl

次行きましょう。systemd-homed は以前の記事で一言だけ紹介した記憶があります。 そのコマンドで homectl というものがあります。

homectl update --setenv FOO=bar

と実行すると、~/.identity ファイルの中に次のように書き込まれます。

"environment" : [
        "FOO=bar"
],

JSON です。この状態でログインすると、環境変数が設定されています。

なお、この環境変数も、PAM 中で設定されます。/etc/pam.d/system-login の中に

-session   optional   pam_systemd.so

という行があり、この pam_systemd.so が設定してくれます。

これも良さそうなのですが、こちらも残念な点が。pam_systemd.so のコード中に以下の部分があります。

https://github.com/systemd/systemd/blob/4ab334472cd1e4a0dd17a4e35e888d380f56ff04/src/login/pam_systemd.c#L545-L549

既に環境変数がセットされていたら、セットしない、という処理です。

PAM のモジュールと言えど、PATH や LANG が設定されていないわけがありません。 つまり、PATH や LANG は homectl で設定しても反映されないのです。

使えね-ー

あ、ちなみに homectl にはいくつか癖がありまして…

  • homectl --setenv は最後に実行したものしか残らない

    つまり、FOO=barBAR=baz を設定しようとして

    homectl --setenv FOO=bar; homectl --setenv BAR=baz

    としても、後者しか残らない、ということです。--setenv は複数書くことができますので、

    homectl --setenv FOO=bar --setenv BAR=baz

    と実行してください。

  • ~/.identity を直接編集しても効果はない

    homectl コマンドなんて使わなくても ~/.identity を直接書けばいいじゃん、と思ったあなた。 それは意味がありません。直接書き換えても反映されません。

    諦めて homectl コマンドを使いましょう。

結局、

どれがいいんでしょう……?

私がぐぐりまくって辿り着いた結論を以下に書きます。

基本的には ~/.zshenv に書きます。しかしそれだけではデスクトップに効果がありませんので、

/usr/share/wayland-sessions/wayfire.desktop:

[Desktop Entry]
Name=Wayfire
Exec=/usr/local/bin/start-wayland-session wayfire
TryExec=wayfire
Icon=
Type=Application
DesktopNames=Wayfire

Exec= の行を書き換えて、 wayfire 起動時に wayfire そのものでなく /usr/local/bin/start-wayland-session を起動するようにします。

/usr/local/bin/start-wayland-session:

#!/bin/bash

if [ -x "$HOME"/.wayland-session ]; then
  exec "$HOME"/.wayland-session "$@"
else
  exec "$@"
fi

こうして、~/.wayland-session があったらそれを実行します。なければ引数の wayfire を そのまま実行します。

~/.wayland-session:

#!/bin/zsh
exec "$@"

このスクリプトは zsh で実行されます。zsh は ~/.zshenv を読み込みますので、そこで 環境変数が設定されます。その後、引数の wayfire を実行します。

まとめ

システム側のファイルを書き換えて解決してしまいました。 以前はユーザ側ファイルだけでなんとかなりました。

最近の Linux デスクトップのヘタレっぷりはとても残念です。 環境変数を一箇所で設定して、いろんなパターンで反映されて欲しい、 たったそれだけのことなのに、何故こんなに悩まないといけないのでしょう? 既に設定されてたら上書きしないとか、意味わかんないです。 設定しろって設定したんだから、ちゃんと設定してくれよ!

ちなみに gdm は PATH を無駄に上書きするので、使うのをやめました。 gdm は複雑すぎるためか、よく不具合起こしますね。

こんなことを愚痴りあえる人が欲しいです。以下のページからお願いします!

https://ingage.co.jp/recruit/

サーバのSSL証明書情報を調べるには?

f:id:ingage:20210519225330p:plain

id:kizashi1122 です。

弊社のサービスを利用しているお客様から「設定したSMTPサーバにうまく接続できない」という問合せを受けることがたまにあります。

接続できない原因としてありえるのが、SSL証明書の問題です。有効期限が切れていたり、接続に使ったドメインと証明書の Common Name が一致してない場合などです。

HTTPS であればブラウザからアクセスし、ブラウザの機能をつかって証明書の内容を確認することができます。

SMTPやPOP3であればどうすればよいでしょうか?

それ、 openssl コマンドを使えばできます。

SMTPS の場合

$ openssl s_client -connect smtp.example.com:465 -showcerts

POP3S の場合

$ openssl s_client -connect pop.example.com:995 -showcerts

SMTP(STRATTLS) の場合

たまに SMTPS には対応しておらず STARTTLS には対応している場合もあります。 そんな場合はこうします。

$ openssl s_client -starttls smtp -crlf -connect smtp.example.com:587

接続後はそのままSMTPのやりとりができます。

便利ですね!

Athena のパーティション設定2種

こんにちは、masm11 です。 今回は AWS Athena のパーティションの設定方法について説明したいと思います。

まず Athena とは

Cloudwatch Logs やその他の場所でログが発生すると、 手軽に検索したくなりますよね。

そういう場合、S3 に置いておくと Athena で SQL を使って検索できます。

発生したログはただのテキストだと思いますので、なんとかして以下のように JSON にしておきます。Cloudwatch Logs に溜まっているなら、Firehose から Lambda を使うのが良いでしょう。

{"timestamp":"2021-04-24T22:50:45","message":"test log 1"}
{"timestamp":"2021-04-24T22:51:00","message":"test log 2"}

こういうファイルをたくさん S3 に溜めておきます。

Athena では以下のように設定します。

CREATE EXTERNAL TABLE logs (
  timestamp string,
  message   string
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://bucket/logs';

こうすると、SQL を使って検索できます。

SELECT * FROM logs WHERE message LIKE 'test log%';

ただし、ここで重大な問題があります。この SQL でスキャンしたデータ量で 料金が発生するのです。なんとかしてスキャンする量を絞る必要があります。

そこでパーティションの出番です。

設定方法その1

S3 バケットの中を以下のように構造化しておきます。 Hive 形式と呼ばれるものです。

s3://bucket/logs/year=YYYY/month=MM/day=DD/file.ext

year= 等はそのままプレフィックスに含めます。YYYY 等は 数字に置き換えます。つまり、プレフィックスには year=2021 等という 文字列が含まれるわけですね。

そして、CREATE EXTERNAL TABLE は以下のように実行します。

CREATE EXTERNAL TABLE logs (
  timestamp string,
  message   string
)
PARTITIONED BY (year STRING, month STRING, day STRING)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://bucket/logs';

その後、

MSCK REPAIR TABLE logs;

を実行します。これで S3 のファイル名がスキャンされて、パーティションの 一覧が作成されます。この時には料金はかかりません。

これで準備ができました。あとは SELECT するだけです。

SELECT * FROM logs WHERE year = '2021' AND month = '04' AND day = '24' AND message LIKE 'test log%';

こうすると、2021-04-24 のログだけがスキャンされます。

ただし、プレフィックスが増えた時には MSCK REPAIR TABLE をしてやる 必要があります。

MSCK REPAIR TABLE だと、ファイル数が増えてくると時間がかかりますので、 代わりに ALTER TABLE ADD PARTITION を使っても良いでしょう。 その場合は、プレフィックスが不要になった場合は ALTER TABLE DROP PARTITION をする必要があります。しなくてもエラーは発生しませんが、 パーティションが増えると検索が遅くなります。

設定方法その2

設定方法その1は、パーティションのメンテが手間なんですよね。 そこで2つめの方法です。

s3://bucket/logs/YYYY/MM/DD/file.ext

year= 等がなくなり、シンプルになりましたね。

CREATE EXTERNAL TABLE は以下のようになります。

CREATE EXTERNAL TABLE logs (
  timestamp string,
  message   string
)
PARTITIONED BY (
  year INT,
  month INT,
  day INT
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://bucket/logs'
TBLPROPERTIES (
  'projection.enabled' = 'true',

  'projection.year.type' = 'integer',
  'projection.year.range' = '2021,2100',
  'projection.year.digits' = '4',

  'projection.month.type' = 'integer',
  'projection.month.range' = '1,12',
  'projection.month.digits' = '2',

  'projection.day.type' = 'integer',
  'projection.day.range' = '1,31'
  'projection.day.digits' = '2',

  'storage.location.template' = 's3://bucket/logs/${year}/${month}/${day}'
);

随分長くなりました。

'projection.day.type' = 'integer',
'projection.day.range' = '1,31'
'projection.day.digits' = '2',

day は整数で、1〜31 で、2桁であることを宣言しています。桁数が足りなければ 0 でパディングされます。

準備はこれで終わりです。検索はその1とだいたい同じですが、年月日は整数になります。

SELECT * FROM logs WHERE year = 2021 AND month = 4 AND day = 24 AND message LIKE 'test log%';

そしてこちらの方法はパーティションのメンテは不要です。

ただし、パーティションのキーはあらかじめ範囲を決めておく必要があります。つまり、

'projection.year.range' = '2021,∞',

なんて指定はできません。

まとめ

Athena のパーティションの設定方法を2つ紹介しました。 特に理由がなければ後者で良いと思います。

インゲージではエンジニアを募集しています。詳細は以下のページへ!

https://ingage.co.jp/recruit/