「俺様サーバー構築記 - 基本方針」以来構築を続けてきた俺様パソコン環境に、Subversionをインストールしました。
これはサーバー用途を想定したデスクトップマシンなので、クライアント用途を想定しているノートパソコン達にもインストールします。接続の際には svn+ssh を使用します。
svn+ssh には幾つかの種類があり、それぞれ特徴があります。
事前準備
ノートパソコン(クライアント側)への Subversion インストール
何はともあれインストール。その前にスナップショットを撮りましょう。万が一の際には rollback できます。
$ su -
パスワード: 〈ノートパソコンのrootのパスワード〉
# zfs snapshot tank/main@$(date +%Y%m%d_%H%M%S)_before_svn
# zfs list -t snapshot -S name | head -n2
NAME USED AVAIL REFER MOUNTPOINT
tank/main@20190715_201435_before_svn 114K - 5.48G -
# pacman -S --noconfirm --noprogressbar svn
〈省略〉
# exit
ログアウト
$ svn --version | head -n2
svn, version 1.12.0 (r1857323)
compiled Jun 7 2019, 01:40:12 on x86_64-pc-linux-gnu
簡易Subversionサーバへの接続確認
ここから先は、Subversionサーバはデスクトップマシンで動いています。まずはその確認。
# systemctl status svnserve
* svnserve.service - Subversion protocol daemon
Loaded: loaded (/usr/lib/systemd/system/svnserve.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/svnserve.service.d
`-override.conf
Active: active (running) since Mon 2019-07-01 21:24:22 JST; 1 weeks 6 days ago
Process: 6371 ExecStart=/usr/bin/svnserve --daemon $SVNSERVE_ARGS (code=exited, status=0/SUCCESS)
Main PID: 6372 (svnserve)
Tasks: 1 (limit: 4915)
Memory: 1.8M
CGroup: /system.slice/svnserve.service
`-6372 /usr/bin/svnserve --daemon -r /srv/svn/repo
Jul 03 23:08:50 server0 svnserve[28616]: DIGEST-MD5 common mech free
Jul 03 23:08:50 server0 svnserve[28628]: DIGEST-MD5 common mech free
Jul 03 23:20:51 server0 svnserve[28808]: DIGEST-MD5 common mech free
Jul 03 23:20:51 server0 svnserve[28821]: DIGEST-MD5 common mech free
Jul 03 23:20:51 server0 svnserve[28828]: DIGEST-MD5 common mech free
Jul 03 23:20:51 server0 svnserve[28835]: DIGEST-MD5 common mech free
Jul 03 23:20:51 server0 svnserve[28840]: DIGEST-MD5 common mech free
Jul 03 23:20:55 server0 svnserve[28886]: DIGEST-MD5 common mech free
Jul 03 23:20:55 server0 svnserve[28893]: DIGEST-MD5 common mech free
Jul 03 23:20:55 server0 svnserve[28898]: DIGEST-MD5 common mech free
テスト用のプロジェクトを作成し、接続先となるサーバマシンのIPアドレスを確認します。
# /srv/svn/createprj.sh test
Edit svnserve.conf and authz in the directory /srv/svn/repo/test/conf as needed.
The file passwd is in the directory /srv/svn/conf, edit it as needed, too.
# hostname -i
10.0.1.121
Subversionに登録しておいたユーザとパスワードを使用して、クライアントマシンにおいてテスト用プロジェクトを操作します。
$ cd
$ mkdir prj
$ cd prj
$ read U
〈Subversionユーザ〉
$ read -s P
〈Subversionユーザのパスワード; 入力しても画面に表示されない〉
$ svn co --username "$U" --password "$P" svn://10.0.0.121/test/
Checked out revision 0.
一応ちゃんとクライアント⇔サーバ間で通信できているようです。
簡易Subversionサーバの停止
最低限の疎通確認が取れたので、現在起動している svnserve は停止させます。
ついでに disable して、サーバマシン再起動時にも動き出さないようにします。
# systemctl stop svnserve
# systemctl disable svnserve
Removed /etc/systemd/system/multi-user.target.wants/svnserve.service.
Subversionクライアント(1) サーバマシンへ ssh 接続可能なユーザの場合
状況の確認
サーバマシン上に home ディレクトリを持つユーザの名前と一致するような Subversion ユーザの場合、全体に共通の設定を1つ作っておけば使い回す事が出来ます。
但し、サーバマシン上のリポジトリである /srv/svn/repo
ディレクトリに設定されているパーミッションに従った不自由が強制される事になります。前回インストールした設定の場合は、ユーザを svn グループに所属させておく必要があります。
今回はユーザ名 taro を例とします。
# grep taro /etc/passwd
taro:x:1000:1000::/home/taro:/bin/bash
# grep taro /srv/svn/conf/passwd
taro = This is 1 pen.
前提条件:
ssh で、クライアント⇔サーバのマシン間通信が出来る。
今回は ssh ではなくて Dropbear になりますが。
$ whoami
taro
$ dbclient -p 60022 10.0.1.121 "whoami"
taro
サーバマシン上での設定
ユーザ taro を svn グループに所属させます。
# usermod -aG svn taro
クライアントマシン上での設定
クライアントマシンの全ユーザ共通設定として、下記のように /etc/subversion/config
ファイルを作成しておきます。
$ su
パスワード:
# mkdir /etc/subversion
# cat >/etc/subversion/config <<___
> [tunnels]
> ssh = dbclient -p 60022
> ___
# exit
動作確認と評価
これで ssh 接続による Subversion 操作が可能になります。…が、リポジトリのフルパス /srv/svn/repo/test
を指定しなければなりません。
$ mkdir prj
$ cd prj
$ svn co svn+ssh://10.0.1.121/srv/svn/repo/test/
リビジョン 0 をチェックアウトしました
$ cd test
$ cat >document.txt <<___
> Twinkle, twinkle, little star
> ___
$ svn add *
A document.txt
$ svn ci -m "first commit"
追加しています document.txt
ファイルのデータを送信しています .done
Committing transaction...
リビジョン 1 をコミットしました。
この手順だと最も簡単な手順で svn+ssh できます。/etc/subversion/config
を一度作成してしまえば、それ以降はマシン内のすべてのユーザで Subversion を使用できるようになります。
その代わり、リポジトリのフルパスを指定しなければなりません。サーバにおけるフルパスをクライアント側で指定するというのは、場合によってはセキュリティ上のリスクにもなるでしょう。
その為か、ArchWiki にはサーバ svnserve のラッパシェルスクリプトを作成して、その中でリポジトリのディレクトリを指定するように書かれています。それだと非常に便利ですが、PATH に指定するディレクトリの順番によって挙動が変わってしまうという副作用があります。忘れた頃に問題が発生して、思い出す為に丸一日潰してしまったとか、そんな碌でもない結果になりそうで怖い…
Subversionクライアント(2) サーバマシンへ ssh 接続可能なユーザに svn 専用キーを作成
先程のユーザ taro を使用します。
# grep taro /etc/passwd
taro:x:1000:1000::/home/taro:/bin/bash
# groups taro
svn taro
# grep taro /srv/svn/conf/passwd
taro = This is 1 pen.
# hostname -i
10.0.1.121
$ whoami
taro
$ dbclient -p 60022 10.0.1.121 "whoami"
taro
サーバマシン上での設定
Subversion に関する基本的な設定、具体的にはリポジトリのディレクトリを、サーバ上に設定ファイルの形で保存しておきます。ファイル名は何でも良いです。今回は basic.conf
にしました。bash で解釈できる文法で記述します。
# cat >/etc/subversion/basic.conf <<'___'
> SVN_HOME=~svn
> SVN_REPO=$SVN_HOME/repo
> ___
クライアント上でのユーザ個別の設定
Subversion 用の秘密鍵と公開鍵を作成
dropbearkey
は標準出力に余計な行も出力するので、それを除いて必要な行だけを公開鍵として保存します。
$ cd ~/.ssh
$ dropbearkey -t ecdsa -s 256 -f id_dropbear_svn | tee >(tail -n+2 | head -n1 >authorized_keys_svn)
Generating 256 bit ecdsa key, this may take a while...
Public key portion is:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIfBpQEUMsuMCYYz564j8JbOjxxr7DZSDYG0lC1qiydfMgth6hXpU84lgAg8smHRpbBn/ZUSEhEiUBoDzSB8OWQ= taro@client0
Fingerprint: sha1!! 7d:13:6d:1d:57:af:85:ff:9e:4e:de:cf:90:d0:f8:cc:f0:4d:7b:4c
$ cat authorized_keys_svn
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIfBpQEUMsuMCYYz564j8JbOjxxr7DZSDYG0lC1qiydfMgth6hXpU84lgAg8smHRpbBn/ZUSEhEiUBoDzSB8OWQ= taro@client0
これをサーバマシンに、svnserve
コマンドの為の指定と共に書き込みます。オプションなどがゴチャゴチャしてますが、詳細は参考文献を見て下さい。
$ cat authorized_keys_svn | dbclient -p 60022 10.0.1.121 'source /etc/subversion/basic.conf; echo command=\"svnserve -tr $SVN_REPO\",no-port-forwarding,no-agent-forwarding,no-pty $(cat) >>~/.ssh/authorized_keys'
Subversion のトンネルスキームを設定
$HOME/.subversion/config
ファイルを下記のように加工します。
$ sed -i -e"/\[tunnels\]/a ssh = dbclient -i $HOME/.ssh/id_dropbear_svn -p 60022" $HOME/.subversion/config
動作確認と評価
$ rm -rf ~/prj
$ mkdir ~/prj
$ cd ~/prj
$ svn co svn+ssh://10.0.1.121/test/
A test/document.txt
リビジョン 1 をチェックアウトしました。
$ cd test
$ cat >>document.txt <<___
> How I wonder what you are
> ___
$ svn ci -m "second commit"
送信しています document.txt
ファイルのデータを送信しています .done
Committing transaction...
リビジョン 2 をコミットしました。
ユーザ毎に個別の設定をしなければならないのが少々面倒ですね。
しかしそれさえ出来れば、サーバ上のフルパスをユーザが把握するなんて危険な事を強制しなくて済みます。
Subversionクライアント(3) サーバマシンに登録されていないユーザの場合
準備
サーバマシンに登録されていないユーザとして、クライアントに新しいユーザ jiro を作成します。
サーバ上に jiro が居ない事を確認。
# grep jiro /etc/passwd | wc -l
0
クライアント上に jiro を作成します。
$ su -
パスワード:
# useradd -m jiro
# passwd jiro
新しいパスワード: 〈jiro のパスワード〉
新しいパスワードを再入力してください: 〈jiro のパスワード〉
passwd: パスワードは正しく更新されました
# exit
サーバ上の設定
Subversion に関する基本的な設定、具体的にはリポジトリのディレクトリを、サーバ上に設定ファイルの形で保存しておきます。先程作成した /etc/subversion/basic.conf
を確認します。
# cat /etc/subversion/basic.conf
SVN_HOME=~svn
SVN_REPO=$SVN_HOME/repo
サーバ上に存在しないユーザで ssh アクセスする為、 svn ユーザとしてログインする事にします。 svn ユーザでログインできるようにし、サーバマシン上の svn ホームディレクトリに .ssh ディレクトリを用意します。
# usermod -s /bin/bash svn
# source /etc/subversion/basic.conf
# cd $SVN_HOME
# mkdir .ssh
# chown svn:svn .ssh
クライアント上でのユーザ個別の設定
ユーザ jiro で秘密鍵と公開鍵のペアを作成し、サーバ上のユーザ svn に対して登録します。登録の際にサーバへアクセスする為、一捻りした手順を実施します。
Subversion 用の秘密鍵と公開鍵を作成
dropbearkey
は標準出力に余計な行も出力するので、それを除いて必要な行だけを公開鍵として保存します。
$ su - jiro
パスワード: 〈jiro のパスワード〉
$ whoami
jiro
$ mkdir .ssh
$ cd .ssh
$ dropbearkey -t ecdsa -s 256 -f id_dropbear_svn | tee >(tail -n+2 | head -n1 >authorized_keys_svn)
Generating 256 bit ecdsa key, this may take a while...
Public key portion is:
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCvHbuWeBbr/3kgb4iqAjkZQH7oJWtWJikBtbiaJi9nsnAS1CqpknFUuC6NxmmOz2Jx8at3vGuQFvbbgPOHIOpc= jiro@client0
Fingerprint: sha1!! 38:94:62:e9:39:6b:2e:04:f3:7a:11:f4:1c:28:b2:c7:6b:4d:5b:40
これをサーバマシンに、svnserve
コマンドの為の指定と共に書き込みます。が、 jiro はサーバに居ないので、サーバに接続できる別のユーザを経由します。そのため手順が少々ややこしくなります。
- サーバに接続できるユーザ taro を利用して、サーバの一時ディレクトリ
/tmp
(のサブディレクトリ)にコピー - サーバ側で
/tmp
(のサブディレクトリ)上の公開鍵を/srv/svn/.ssh
の公開鍵置き場にコピー - その際、同時に
svnserve
コマンドの為の指定を書き込みます。オプションなどがゴチャゴチャしてますが、詳細は参考文献を見て下さい。
$ su
パスワード:
# cat ~jiro/.ssh/authorized_keys_svn | dbclient -l taro -i ~taro/.ssh/id_dropbear -p 60022 10.0.1.121 "mkdir /tmp/jiro; cat >/tmp/jiro/authorized_keys_svn"
Host '10.0.1.121' is not in the trusted hosts file.
(ecdsa-sha2-nistp256 fingerprint sha1!! c9:c0:6f:79:53:a6:17:b2:27:82:ee:a3:c9:a0:92:23:db:0d:fc:82)
Do you want to continue connecting? (y/n) y
# rm -rf $HOME/.ssh
# exit
/srv/svn/.ssh/authorized_keys
ファイルに jiro の公開鍵を登録します。
# cd /tmp/jiro
# source /etc/subversion/basic.conf
# SVN_USER=$(cat authorized_keys_svn | cut -d" " -f3 | cut -d@ -f1)
# cat >>$SVN_HOME/.ssh/authorized_keys <<___
> command="svnserve -tr $SVN_REPO --tunnel-user=$SVN_USER",no-port-forwarding,no-agent-forwarding,no-pty $(cat authorized_keys_svn)
> ___
# cd
# rm -r /tmp/jiro
Subversion のトンネルスキームを設定
jiro に $HOME/.subversion/config
ファイルを作る為に、適当に svn コマンドを実行します。当然、エラーになりますが、それで良いのです。
(2019/08/06 修正ここから)
エラーにならないコマンドとして svn --version
を実行します。それでも $HOME/.subversion
は作成されますので。そして config
ファイルを修正します。
$ whoami
jiro
$ svn --version >/dev/null
$ sed -i -e"/\[tunnels\]/a ssh = dbclient -l svn -i $HOME/.ssh/id_dropbear_svn -p 60022" $HOME/.subversion/config
(2019/08/06 修正ここまで)
動作確認と評価
(2019/08/06 修正ここから)
svn --version
コマンドを実行したので、ssh に関してのメッセージがここで表示されるようになります。
$ whoami
jiro
$ mkdir ~/prj
$ cd ~/prj
$ svn co svn+ssh://10.0.1.121/test/
Host '10.0.1.121' is not in the trusted hosts file.
(ecdsa-sha2-nistp256 fingerprint sha1!! c9:c0:6f:79:53:a6:17:b2:27:82:ee:a3:c9:a0:92:23:db:0d:fc:82)
Do you want to continue connecting? (y/n)
A test/document.txt
リビジョン 2 をチェックアウトしました。
$ cd test
$ cat >>document.txt <<___
> Up above the world so high
> ___
$ svn ci -m "third commit"
送信しています document.txt
ファイルのデータを送信しています .done
Committing transaction...
リビジョン 3 をコミットしました。
$ svn log -r HEAD --xml | xmllint --xpath '/log/logentry/author/text()' -
jiro
(2019/08/06 修正ここまで)
commit したユーザはきちんと jiro になっています。
この方法の最大の特徴は、サーバに登録されたユーザでなくても Subversion へアクセスできる点です。その分、公開鍵を正しく svn ユーザに届けて登録する手順が面倒になりますが。
サーバに登録されていないユーザでの Subversion アクセスと言うと、最も有用な使い方の一つは root ユーザによるバージョン管理でしょう。例えば /etc
のバージョン管理です。
先の発展の足掛かりを得られました。やったね