さくらVPSのOSをCentOS 8に更新、さらにRedmineを4.1に更新(続々々)
さくらVPSのOSをCentOS 8に、Redmineを4.1に更新、の続き(4日目)
先日の続きです。
Redmineログのローテーション
SELinux下でlogrotateを使ってRedmineのログ・ローテーションを実現するには設定がそれなりに手間なので、Railsの機能を使ってログローテーションを設定します。
Redmineインストールディレクトリのconfig/additional_environment.rb にログ設定を記述
config.logger = Logger.new('log/production.log', 30, 10 * 1024 * 1024)
- 一つ目の引数は、ログファイルのパスを指定します。Railsアプリケーションのルートディレクトリからの相対パスで指定可。
- 二つ目の引数は、ローテートするときに残す世代数(ファイル数)です。
- 三つ目の引数は、ログファイルの容量がこの閾値に達したらローテーションを実施する値です。
gitサーバー
このマシンに共有gitリポジトリを設けて、Redmineから参照し、またHTTP経由でリポジトリのクローンとプッシュをできるようにします。
HTTPからのアクセスにおいて、HTTP用にアカウントを作成し運用管理するのは負担が大きいですから、RedmineのアカウントでHTTPの認証を行うようにします。Redmineには現時点ではApache HTTPD用の認証モジュールが含まれていますがNginxには対応していません。
https://www.redmine.org/issues/7061
そこで、Git(Subversion)リポジトリアクセス用にApache HTTPDをインストールします。
gitリポジトリの格納ディレクトリとSELinux許可
gitリポジトリに対しては、読み込み、書き込み、およびスクリプトの実行が必要です。HTTP経由でgitリポジトリにアクセスするには、HTTPのプロセスに与えられるドメインhttpd_tから、gitリポジトリのリソースに対する読み込み(map操作含む)、書き込み、スクリプト実行の操作の許可があるリソースタイプをgitリポジトリに割当てます。
CentOS 8のデフォルトSELinux設定では、gitリポジトリを置くと想定しているディレクトリに対して次のリソースタイプが割当てられています。また、ディレクトリ内のファイルに対して許可される操作も併記します。調査コマンドについては後述します。
基点ディレクトリ | リソースのタイプ | ドメインhttpd_tからファイルへの許可された操作 |
---|---|---|
/var/lib/git | git_sys_content_t | getattr ioctl lock map open read |
/var/www/git | git_content_t | getattr ioctl lock map open read |
これらのデフォルトSELinux設定では、書き込み操作およびスクリプトの実行操作が許可されていません。 そこで、書き込み操作と、必要なディレクトリに限定して実行操作を許可するリソースタイプを設定します。
- ドメインhttpd_tから/var/lib/git 以下のリソースに対して読み書き許可
- ドメインhttpd_tから/var/lib/git/<リポジトリ名>/hooks 以下のリソースに対して実行許可
ドメインhttpd_tから上述の許可を持つリソースタイプを調査したところ、次のタイプが適しています。
- git_rw_content_t
- git_script_exec_t
SELinuxのポリシー設定を変更します。
/var/lib/git/下のリポジトリディレクトリは、読み書きが可能なgit_rw_content_tを割当てます。デフォルトでルール定義があるので-mオプションで変更するコマンドを実行します。
# semanage fcontext -m -t git_rw_content_t '/var/lib/git(/.*)?'
各リポジトリディレクトリ下のhooks/ディレクトリは、この中にあるスクリプトを実行できるようSELinuxのタイプをgit_script_exec_tに割当てます。
# semanage fcontext -a -t git_script_exec_t '/var/lib/git/[^/]+/hooks(/.*)?'
/var/lib/gitディレクトリを作成し、念のためSELinuxのリソースを再割り当てしておきます。
# mkdir /var/lib/git # restorecon -R /var/lib/git
リソースに割り当てられるタイプの調査
# semanage fcontext -l | grpe git : /var/lib/git(/.*)? all files system_u:object_r:git_sys_content_t:s0 /var/www/git(/.*)? all files system_u:object_r:git_content_t:s0 :
ドメインhttpd_tからリソースへのアクセス可能な操作の調査
ドメインhttpd_tからタイプgit_sys_content_tへの許可を調べるコマンドの実行例を以下に示します。
$ sesearch -A -s httpd_t -t git_sys_content_t allow httpd_t file_type:dir { getattr open search }; allow httpd_t file_type:filesystem getattr; allow httpd_t git_sys_content_t:dir { getattr ioctl lock open read search }; allow httpd_t git_sys_content_t:file { getattr ioctl lock map open read }; allow httpd_t git_sys_content_t:lnk_file { getattr read };
- ここで実行結果にあるリソースタイプがfilte_typeと末尾が_typeで終わる表記となっています。これはアトリビュートを示します。アトリビュートは複数のリソースタイプを束ねたものです。git_sys_content_tタイプもfile_typeに束ねられているのでsesearchコマンドの結果として表示されています。参考資料は次(p.16のスライドに記載あり) www.slideshare.net
ドメインhttpd_tからタイプgit_content_tへの許可を調べるコマンドの実行例を以下に示します。
$ sesearch -A -s httpd_t -t git_content_t allow httpd_t httpd_content_type:dir { getattr ioctl lock open read search }; [ httpd_builtin_scripting ]:True allow httpd_t httpd_content_type:dir { getattr open search }; allow httpd_t httpd_content_type:dir { getattr open search }; [ httpd_builtin_scripting ]:True allow httpd_t httpd_content_type:dir { getattr open search }; [ httpd_builtin_scripting ]:True allow httpd_t httpd_content_type:dir { getattr open search }; [ httpd_builtin_scripting ]:True allow httpd_t httpd_content_type:file { getattr ioctl lock map open read }; allow httpd_t httpd_content_type:file { getattr ioctl lock open read }; [ httpd_builtin_scripting ]:True allow httpd_t httpd_content_type:lnk_file { getattr read }; [ httpd_builtin_scripting ]:True
アトリビュートに束ねられているリソースタイプの確認方法は次です。
$ seinfo --attribute=httpd_content_type -x Type Attributes: 1 attribute httpd_content_type; apcupsd_cgi_content_t apcupsd_cgi_htaccess_t : git_content_t git_htaccess_t git_ra_content_t git_rw_content_t git_script_exec_t httpd_sys_content_t httpd_sys_htaccess_t httpd_sys_ra_content_t httpd_sys_rw_content_t httpd_sys_script_exec_t httpd_user_htaccess_t httpd_user_ra_content_t :
ドメインhttpd_tから、指定の操作が可能なリソースタイプを調査
$ sesearch -A -s httpd_t -c file -p write : allow httpd_t git_rw_content_t:file { append create getattr ioctl link lock open read rename setattr unlink write }; [ httpd_builtin_scripting ]:True
バックアップしていたgitリポジトリの復元
/var/lib/git ディレクトリの下に、バックアップしていたgitリポジトリを展開します。 (今回はtarで固めたバックアップファイルを単に展開)
# cd /var/lib/git # tar xzf ~/git_swe_primus-20200423.git.tgz # ls swe.primus.git # restorecon -R .
展開後、SELinuxのタイプが正しく付いていないこともあるので、restoreconで反映します。 また、次の手順でApache httpdをインストールした後で、ファイルのパーミッションをapacheに変更します。
Apache httpd のセットアップ
Redmineと連携するリポジトリアクセス用Webサーバーには、Apache HTTPDを使います。 既にWebサーバーにはNginxを稼働させているので、ポート番号をずらしてApache HTTPDを稼働します。
Apache HTTPDのインストール
Apache httpd は、モジュールとして提供されています。
# dnf module list httpd CentOS-8 - AppStream Name Stream Profiles Summary httpd 2.4 [d] common [d], devel, minimal Apache HTTP Server ヒント: [d]efault, [e]nabled, [x]disabled, [i]nstalled
現時点ではバージョンは1つだけ存在するので、そのままモジュールをインストールします。
# dnf module install httpd :
Apache HTTPDの動作方式
Apache HTTPDが同時に複数のリクエストを受けて動作する際の並行処理の動作方式には複数の種類があります。Multi Processing Module: MPMと呼ばれる動作方式には、prefork、worker、eventの3種類があり、今回インストールしたCentOS 8のモジュールではデフォルトがeventになっています。 preforkは古のApache httpdからあるシングルスレッドプロセスを複数稼働させ、1リクエストを1プロセスで受ける方式、workerとeventはマルチスレッドプロセスを複数稼働させ、複数リクエストを1プロセスで受ける方式です。
- /etc/httpd/conf.modules.d/00-mpm.conf
この設定ファイルで方式に応じたsoをLoadModuleします。
さて、Redmine認証連携のためにmod_perlを使用しますが、このmod_perlは古いので event方式で支障なく動くものなのか確証がありません。そこで今回はMPM方式をpreforkに変更します。
- #LoadModule mpm_prefork_module modules/mod_mpm_prefork.so + LoadModule mpm_prefork_module modules/mod_mpm_prefork.so - LoadModule mpm_event_module modules/mod_mpm_event.so + #LoadModule mpm_event_module modules/mod_mpm_event.so
また、子プロセス数等のpreforkの設定を記述するファイルを用意します。gitリポジトリへのアクセスに使うだけのHTTPDで、仮想マシンでCPU数もほとんどないので、起動プロセス数は最小限にします。
- /etc/httpd/conf.d/mpm.conf
<IfModule mpm_prefork_module> # 起動時に生成する子プロセス数 StartServers 2 # アイドルな子プロセスの最小個数 MinSpareServers 2 # アイドルな子プロセスの最大個数 MaxSpareServers 2 # 子プロセス数の設定可能な上限 ServerLimit 2 # 最大同時リクエスト数 MaxRequestWorkers 2 # 子プロセスが稼働中に扱うリクエスト数の上限 MaxConnectionsPerChild 4 </IfModule>
Apache HTTPDのデフォルトポート変更
既にNginxがポート80を使用しているので、Apache httpdはポートをデフォルトの80から8008等に変更します。SELinuxではhttpdプロセス(ドメインhttpd_t)がbindできるポートも制限がかけられています。
SELinuxの設定を変更することなく利用可能なポート番号の調べ方は次です。
http_port_t が対象とするポート番号を確認します。
# semanage port -l : http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000 :
ドメインhttpd_t は、http_port_t に対して name_bind 操作が許されています。
$ sesearch -A -s httpd_t : allow httpd_t http_port_t:tcp_socket name_bind; :
-Listen 80 +Listen 8008 -ServerName +ServerName www.torutk.com:8008
Apache httpdのデフォルト設定変更(不要な設定の削除)
/etc/httpd/conf.d/ にある設定ファイルのうち使用しないものを削除(またはリネーム)します。
# cd /etc/httpd/conf.d # mv welcome.conf welcome.conf.orig # mv autoindex.conf autoindex.conf.orig # mv ssl.conf ssl.conf.orig # mv userdir.conf userdir.conf.orig
SSLモジュールを読み込まないよう設定を変更します。
- LoadModule ssl_module modules/mod_ssl.so + #LoadModule ssl_module modules/mod_ssl.so
Apache httpd経由のGitリポジトリ動作確認
まずはRedmine認証連携の前に、Apache httpdの起動とGitリポジトリ動作確認をします。
SetEnv GIT_PROJECT_ROOT /var/lib/git SetEnv GIT_HTTP_EXPORT_ALL SetEnv REMOTE_USER $REDIRECT_REMOTE_USER ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/ <LocationMatch "^/git/"> Require all granted </LocationMatch>
認証はしないので、Require には"all granted"を記述します。
ポート8008を一時的に開きます。
# firewall-cmd --add-port=8008/tcp
# systemctl start --now httpd
# cd /var/lib/git # chown -R apache:apache *
リモートからhttp経由でクローンと変更のプッシュを行い、動作確認をします。 まずクローンを実行します。
D:\work> git clone http://www.torutk.com:8008/git/swe.primus.git Cloning into 'swe.primus'... remote: Enumerating objects: 739, done. remote: Counting objects: 100% (739/739), done. remote: Compressing objects: 100% (279/279), done. remote: Total 739 (delta 232), reused 739 (delta 232)Receiving objects: 100% (739/739), 20.23 MiB | 20.23Receiving objects: 100% (739/739), 20.67 MiB | 20.06 MiB/s, done. Resolving deltas: 100% (232/232), done.
変更をローカルでコミット後、プッシュします。
D:\work\swe.primus>git push Enumerating objects: 5, done. Counting objects: 100% (5/5), done. Delta compression using up to 6 threads Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 273 bytes | 136.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0) To http://www.torutk.com:8008/git/swe.primus.git 40ba3f1..6bd5f2d master -> master
mod_perlのインストールとRedmine認証設定
Redmineの認証を利用して、Git(Apache HTTPD)の認証を行います。 Redmineに同梱されている Redmine.pm (Perlモジュール)を、httpdのmod_perlの検索パスに置きます。
# mkdir -p /etc/httpd/Apache/Authn # sudo ln -s /var/lib/redmine/extra/svn/Redmine.pm /etc/httpd/Apache/Authn/Redmine.pm
このRedmine.pmをApache HTTPDから利用するために、HTTPDにmod_perl モジュールを追加する必要があります。mod_perlは少々古い仕組みで、CentOS 7以降はOS標準には含まれなくなっているので、EPELリポジトリから取得します。
EPELリポジトリ利用設定をインストールします。
# dnf install epel-release
EPELリポジトリからパッケージをインストールするのは限定的とするため、デフォルトではEPELリポジトリを無効とする設定に変更します。
- /etc/yum.repos.d/epel.repo
[epel] name=Extra Packages for Enterprise Linux $releasever - $basearch #baseurl=https://download.fedoraproject.org/pub/epel/$releasever/Everything/$basearch metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch&infra=$infra&content=$contentdir - enabled=1 + enabled=0 gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
mod_perlをインストールします。
# dnf --enablerepo=epel install mod_perl :
perl-Digest-SHAをインストールします。
# dnf install perl-Digset-SHA :
/etc/httpd/conf.d/git-redmine.conf に追記
+ PerlLoadModule Apache::Authn::Redmine SetEnv GIT_PROJECT_ROOT /var/lib/git SetEnv GIT_HTTP_EXPORT_ALL SetEnv REMOTE_USER $REDIRECT_REMOTE_USER ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/ <LocationMatch "^/git/"> + PerlAccessHandler Apache::Authn::Redmine::access_handler + PerlAuthenHandler Apache::Authn::Redmine::authen_handler + AuthType Basic + AuthName "Git Redmine" + AuthUserFile /dev/null + RedmineDSN "DBI:mysql:database=redmine;host=localhost" + RedmineDbUser "redmine" + RedmineDbPass "XXXXXX" + RedmineGitSmartHttp yes - Require all granted + Require valid-user </LocationMatch>
以前のApache httpd + Gitでは、AuthUserFile /dev/null
は不要だったかと思いますが、現時点ではこの指定が必要です([authn_file:error] AH01619: AuthUserFile not specified in the configuration
が出る)。
この設定ファイルにはRedmineのMySQLデータベースへの接続情報が記載されるので、アクセス権を厳し目に設定します。
# chmod 0400 /etc/httpd/conf.d/git-redmine.conf
# systemctl reload httpd
Nginxのhttps経由でのアクセス
ここまでの設定でGitリポジトリへの読み書きのアクセスができるようになりました。 しかし、httpプロトコルでポート8008にアクセスしており、認証はBasicのため平文で流れてしまいます。
せっかくサーバーにSSLサーバー証明書を設置し、セキュアなアクセスができるようになっているので、SSLでGitリポジトリにアクセスしたいところです。
既にNginxがhttps(ポート443)を押さえているので、Apache HTTPDにSSL設定をすることができません。そこで、Ngixを経由してApacheにアクセスすることでSSLを利用します。
- /etc/nginx/conf.d/redmine.conf に追記
location ^~ /.well-known/acme-challenge/ { root /usr/share/nginx/html; } + location ^~ /git/ { + proxy_pass http://localhost:8008; + } location / { try_files /maintenance.html $uri/index.html $uri.html $uri @app; }
この設定で、Nginxがポート80もしくは443でgitへのアクセスを受けると、localhostの8008に転送します。 しかし、これだけではSELinuxでエラーになってしまいます。ドメインhttpd_tが別なプロセスにTCP接続するには許可が必要になります。
SELinuxのブール値設定で、httpd_can_network_relay を on にします。
# getsebool -a | grep httpd_can_network httpd_can_network_connect --> off httpd_can_network_relay --> off # setsebool -P httpd_can_network_relay on # getsebool httpd_can_network_relay httpd_can_network_relay --> on