ねじまきまきまき -Random Note-

やったこと忘れないための雑記

certbotコマンドのオプション指定について

cetbot用cron設定見直し

cronの設定値

現在の設定内容は以前も書いたが以下のような感じ。

certbotコマンドが正常終了となったらstone再起動用のbashを起動している。

00 00 01  \*  \* sudo /usr/bin/certbot renew && /Local/stone_run.bash 1>/dev/null 2>&1 &

ただし、わざわざ&&でコマンドをつなげることをせずともオプションとかを使用すれば、再起動できるっぽい。

certbotコマンドの再考

usageはこんな感じ。

$ certbot --help renew
usage: 

  certbot renew [--cert-name CERTNAME] [options]

optional arguments:
  -h, --help            show this help message and exit
  -c CONFIG_FILE, --config CONFIG_FILE
                        path to config file (default: /etc/letsencrypt/cli.ini
                        and ~/.config/letsencrypt/cli.ini)

renew:
  The 'renew' subcommand will attempt to renew all certificates (or more
  precisely, certificate lineages) you have previously obtained if they are
  close to expiry, and print a summary of the results. By default, 'renew'
  will reuse the options used to create obtain or most recently successfully
  renew each certificate lineage. You can try it with `--dry-run` first. For
  more fine-grained control, you can renew individual lineages with the
  `certonly` subcommand. Hooks are available to run commands before and
  after renewal; see https://certbot.eff.org/docs/using.html#renewal for
  more information on these.

  --cert-name CERTNAME  Certificate name to apply. This name is used by
                        Certbot for housekeeping and in file paths; it doesn't
                        affect the content of the certificate itself. To see
                        certificate names, run 'certbot certificates'. When
                        creating a new certificate, specifies the new
                        certificate's name. (default: the first provided
                        domain or the name of an existing certificate on your
                        system for the same domains)
  --dry-run             Perform a test run of the client, obtaining test
                        (invalid) certificates but not saving them to disk.
                        This can currently only be used with the 'certonly'
                        and 'renew' subcommands. Note: Although --dry-run
                        tries to avoid making any persistent changes on a
                        system, it is not completely side-effect free: if used
                        with webserver authenticator plugins like apache and
                        nginx, it makes and then reverts temporary config
                        changes in order to obtain test certificates, and
                        reloads webservers to deploy and then roll back those
                        changes. It also calls --pre-hook and --post-hook
                        commands if they are defined because they may be
                        necessary to accurately simulate renewal. --deploy-
                        hook commands are not called. (default: False)
  --force-renewal, --renew-by-default
                        If a certificate already exists for the requested
                        domains, renew it now, regardless of whether it is
                        near expiry. (Often --keep-until-expiring is more
                        appropriate). Also implies --expand. (default: False)
  --allow-subset-of-names
                        When performing domain validation, do not consider it
                        a failure if authorizations can not be obtained for a
                        strict subset of the requested domains. This may be
                        useful for allowing renewals for multiple domains to
                        succeed even if some domains no longer point at this
                        system. This option cannot be used with --csr.
                        (default: False)
  -q, --quiet           Silence all output except errors. Useful for
                        automation via cron. Implies --non-interactive.
                        (default: False)
  --preferred-chain PREFERRED_CHAIN
                        If the CA offers multiple certificate chains, prefer
                        the chain with an issuer matching this Subject Common
                        Name. If no match, the default offered chain will be
                        used. (default: None)
  --preferred-challenges PREF_CHALLS
                        A sorted, comma delimited list of the preferred
                        challenge to use during authorization with the most
                        preferred challenge listed first (Eg, "dns" or
                        "http,dns"). Not all plugins support all challenges.
                        See https://certbot.eff.org/docs/using.html#plugins
                        for details. ACME Challenges are versioned, but if you
                        pick "http" rather than "http-01", Certbot will select
                        the latest version automatically. (default: [])
  --pre-hook PRE_HOOK   Command to be run in a shell before obtaining any
                        certificates. Intended primarily for renewal, where it
                        can be used to temporarily shut down a webserver that
                        might conflict with the standalone plugin. This will
                        only be called if a certificate is actually to be
                        obtained/renewed. When renewing several certificates
                        that have identical pre-hooks, only the first will be
                        executed. (default: None)
  --post-hook POST_HOOK
                        Command to be run in a shell after attempting to
                        obtain/renew certificates. Can be used to deploy
                        renewed certificates, or to restart any servers that
                        were stopped by --pre-hook. This is only run if an
                        attempt was made to obtain/renew a certificate. If
                        multiple renewed certificates have identical post-
                        hooks, only one will be run. (default: None)
  --deploy-hook DEPLOY_HOOK
                        Command to be run in a shell once for each
                        successfully issued certificate. For this command, the
                        shell variable $RENEWED_LINEAGE will point to the
                        config live subdirectory (for example,
                        "/etc/letsencrypt/live/example.com") containing the
                        new certificates and keys; the shell variable
                        $RENEWED_DOMAINS will contain a space-delimited list
                        of renewed certificate domains (for example,
                        "example.com www.example.com" (default: None)
  --disable-hook-validation
                        Ordinarily the commands specified for --pre-hook
                        /--post-hook/--deploy-hook will be checked for
                        validity, to see if the programs being run are in the
                        $PATH, so that mistakes can be caught early, even when
                        the hooks aren't being run just yet. The validation is
                        rather simplistic and fails if you use more advanced
                        shell constructs, so you can use this switch to
                        disable it. (default: False)
  --no-directory-hooks  Disable running executables found in Certbot's hook
                        directories during renewal. (default: False)
  --disable-renew-updates
                        Disable automatic updates to your server configuration
                        that would otherwise be done by the selected installer
                        plugin, and triggered when the user executes "certbot
                        renew", regardless of if the certificate is renewed.
                        This setting does not apply to important TLS
                        configuration updates. (default: False)
  --no-autorenew        Disable auto renewal of certificates. (default: True)

これを見ると、cronなどで自動実行する場合はquietオプションを推奨されている。

また、pre-hook/post-hook/deploy-hookの各オプションでcertbot動作前後や証明書更新が行われた場合のみの処理も行うことが可能っぽい。

このhookオプションは/etc/letsencrypt/renewal-hooks配下にファイルを置くことでも代替できるようなので、用途を考えるとオプションよりもディレクトリにファイルを置いたほうがいいのかもしれない。

新しいcron用コマンド

上記の考察から、quietオプションとpost-hookオプションを使用するとこうなる。

sudo /usr/bin/certbot renew --quiet --post-hook /Local/stone_run.bash

stoneの起動シェルの変更

stone用の起動シェルについてもこのタイミングでいろいろ見直しを行った。

というのも、一度/etc/letsencrypt/renewal-hooks配下にシンボリックリンクを作成する想定で動作を見ていた時に不具合が発生することがわかったためだ。

以下が修正後の起動シェルになる。

例のごとく、シェルと同ディレクトリにあるstone.+confファイルの数だけ処理を繰り返すというところは変わらない。

変わったのはBASE_DIR変数の取得方法で、dirnameに直接$0を渡すのを止め、realpathコマンドをかます形になっている。

これはシンボリックリンクを動作させた場合、$0に設定されるのはシンボリックリンクのパスなので、シェルファイル自体のパスを取得するための変更となっている。

ちなみにreadlinkではなくrealpathとしているのは、この方法ではreadlinkが想定した動作をしてくれなかったためとなる。

readlinkコマンドを使って$(dirname $(readlink -e $0))みたいなことをやってみたところ、どうもうまく動作しなかったので、ワンラインで動作できたrealpathコマンドで代替した感じ。

#!/bin/bash -l

#BASE_DIR=`dirname $0`
BASE_DIR=`dirname $(realpath $0)`
cd ${BASE_DIR}

## Kill
if [ `ps -ef | egrep "stone.+conf" | egrep -v "grep|sudo|bash" | wc -l` -ne 0 ]; then
        for stone_proc in `ps -ef| egrep "stone.+conf" | egrep -v "grep|sudo|bash" | awk '{print $2}'`
        do
                sudo kill -9 ${stone_proc}
        done
fi

sleep 10

## Start
while true
do
        for target_conf in `ls stone*.conf`
        do
                        if [ `ps -ef | egrep ${target_conf} | egrep -v "grep|sudo|bash" | wc -l` -eq 0 ]; then
                                        nohup sudo /usr/local/bin/stone -C ${BASE_DIR}/${target_conf} 1>/dev/null 2>&1 &
                        fi
        done

        if [ `ps -ef | egrep "stone.+conf" | egrep -v "grep|sudo|bash" | wc -l` -eq `ls stone*.conf | wc -l` ]; then
                break
        else
                sleep 10
        fi
done

exit 0

動作検証

検証というほどでもないが、これがうまく動くことを確認するため、quietオプションを外して、dry-runオプションを付けた状態で動かしてみる。

$sudo /usr/bin/certbot renew --dry-run --post-hook /Local/stone_run.bash
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator standalone, Installer None
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Simulating renewal of an existing certificate for example.com
Performing the following challenges:
http-01 challenge for example.com
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/example.com/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded: 
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: /Local/stone_run.bash

予定通りの結果が得られたので、これでいいこととする。

エクスプローラーで狙ったフォルダを開くワンライナー

同じ処理を書けと言われても思い出せない

前提として、WSLを使えばたぶん行けるけど、その方法は今回パス。

主に仕事用のWindowsPCで使うことを想定して、だけど。

メールとかいろんなもので共有されたパスのフォルダをエクスプローラーで開くってのがそこそこにある。

ファイル名を指定して実行のダイアログとかエクスプローラーのアドレス履歴に貼り付けてってのがだいたいの遷移方法だと思う。

自分の場合は、ファイル名を指定して実行のダイアログを呼び出したり、エクスプローラーを起動したりってのがどうにも億劫に感じていた。

今まではVBSを使用して該当フォルダを開くっていうスクリプトを作っていて、ツールバースクリプトショートカットを置いて、それを起動すれば動くみたいな感じのものを使っていた。

一応VBSのものはVBSのものでエラーハンドリングもしていたし、当時使用してたコミュニケーションツールでパスを装飾することになっていたので、その装飾文字を除外するみたいな機能も盛り込んでいたりした。

機能としてはやることが単純なので、特に不満はないのだが、如何せん同じものを作ろうとしたときに、すぐに思い出せる気がしてならないのが難点。

ということで、コマンドプロンプトとかPowerShellあたりでどうにかできないかなーって思ってやってみた。

やりかたをいろいろ検討

例えば、コマンドでクリップボード操作が行える場合は、その結果を使えそう。

このためにclipコマンドを見てみるとこんな感じ。

clip /?

CLIP

説明:
    コマンド ライン ツールの出力を Windows クリップボードにリダイレクトします。
    その出力されたテキストをほかのプログラムに貼り付けることができます。

パラメーター一覧:
    /?                  このヘルプを表示します。

例:
    DIR | CLIP          現在のディレクトリ一覧のコピーを Windows クリップボード
                        に貼り付けます。

    CLIP < README.TXT   readme.txt ファイルのテキストのコピーを Windows
                        クリップボードに貼り付けます。

これを見る限り、クリップボードに入れることは出来ても出すことは無理。

コマンドが駄目だとすれば、PowerShellのコマンドレットではどうか。

docs.microsoft.com

しっかりとクリップボードから値を取得すると書かれている。

ということで、PowerShellを使用すれば値の取得は簡単にできることが分かった。

ではどうやって実行するか

値を取得したとしてもそれをどうやって実行するかだが、startコマンドやexplorerコマンドに引数として値を渡すことができればいい。

こういう場合、LinuxとかUnixではxargsコマンドを使って別コマンドに引数を渡すことができる。

例として、/hoge/fugaから一般ファイルで、ファイル拡張子がtxtのファイルを探して、それらのls -lの結果を標準出力する場合はこんな感じ。

find /hoge/fuga -type f -name "\*.txt" | xargs ls -l

ということで、コマンドプロンプトで同じようなことができないかと見てみたが、どうやらxargs相当のコマンドはないということだけがわかった。

パイプ"|"を使用することで、左のコマンド結果を右コマンドの標準入力に送り込めるというは変わらないようだけど、やりたいことは引数に値を与えたいので、この方法は使えない。

ということで、Powershellのみでクリップボードを取得して、取得した値を開くという動作を行うことをやってみる。

コマンドレットの確認

www.atmarkit.co.jp

www.atmarkit.co.jp

Get-Clipboardは先述の通り、値をとってくる。

Invoke-Itemはファイルやフォルダを開く。

ということで、この2つのコマンドレットでできるっぽい。

以下でやっていることはここでやっていることと同じ。 loner49th.hatenablog.com

とりあえず、PowerShellを起動して、以下を打ち込んでみるとうまく動作することが見て取れる。 ※実行前にクリップボードに「C:\」とかをコピーしておく。

$extPath = Get-Clipboard
Invoke-Item $extPath

PowerShellスクリプトのセキュリティ対応

PowerShellスクリプトはセキュリティ設定によって、初期状態では実行できないようになっている。 www.atmarkit.co.jp

これを回避するために、起動用のbatを管理者権限で実行して、PowerShellスクリプトの実行許可設定を変更ののちにPowerShellスクリプトを実行。

その後に実行許可設定を元に戻すことがある。

とはいえ、この2行を実行するためにわざわざそんなことをやるぐらいなら、そんなものは作りたくないというのもあるので、powershellコマンドに実行処理を引数で渡す方法にて実現してみる。

起動方法

以下に記載の通り、powershellコマンドに引数で処理内容を記載して実行する。

powershellコマンドは引数をセミコロン";"で区切ることで、ワンライナーが実現できる。

この処理実行はコマンドプロンプトから実行できる。

powershell $extPath = Get-Clipboard; Invoke-Item $extPath

後はこれを記載したrun.batみたいなbatファイルを用意しておけば、コマンドプロンプトが起動してやりたいことをやってくれる。

ちなみに実行時にコマンドプロンプトのウインドウが表示されるのも煩わしいという場合は、batファイルのショートカットを作成し、ショートカットのプロパティから実行時の大きさを最小化に設定すればよい。

サーバーのSSL/TSLテストをやってみる

サーバーのSSL/TLSテストについて

CMAN

CMAN SSLチェック【証明書・プロトコル・暗号スイート確認】

日本語で使えるので、いろいろ使いやすいが、TLS1.3に対応していない。

SSL Server Test

Qualys SSL Server Test

サーバーのSSLテストでよく使われるらしい。

ただし、有料プランでなければ標準ポート(443)以外のチェックが行えないため、標準ポート以外でチェックしたい場合はできない。

testssl.sh

tsetss testssl(git)

WebサーバーのSSL/TLSの対応状況とか、使用可能な証明書アルゴリズムとか脆弱性の対応状況を一括で確認できるbashスクリプト

拡張子が「sh」となっているが、中身を見てみるとどうやら「bash」っぽい。

bashが使用できるシステムであればたぶん汎用的に使用できる。

ポートについても443以外のカスタムポートをチェックすることも可能。

testssl.shでやってみる

wgetでもgitでもいいので、とりあえずダウンロードして動かしてみるといろいろわかる。

usageはこんな感じ。

もちろん、オプションなしでtestssl.shを実行すれば同じものが見ることができる。

$ ./testssl.sh

     "testssl.sh [options] <URI>"    or    "testssl.sh <options>"

"testssl.sh <option>", where <option> is mostly standalone and one of:

     --help                        what youre looking at
     -b, --banner                  displays banner + version of testssl.sh
     -v, --version                 same as previous
     -V, --local [pattern]         pretty print all local ciphers (of openssl only). If search pattern supplied: it is an
                                   an ignore case word pattern of cipher hexcode or any other string in its name, kx or bits

"testssl.sh [options] <URI>", where <URI> is:

     <URI>                         host|host:port|URL|URL:port   port 443 is default, URL can only contain HTTPS as a protocol

  and [options] is/are:

     -t, --starttls <protocol>     Does a run against a STARTTLS enabled service which is one of ftp, smtp, lmtp, pop3, imap,
                                   xmpp, xmpp-server, telnet, ldap, nntp, postgres, mysql
     --xmpphost <to_domain>        For STARTTLS xmpp or xmpp-server checks it supplies the domainname (like SNI)
     --mx <domain/host>            Tests MX records from high to low priority (STARTTLS, port 25)
     --file/-iL <fname>            Mass testing option: Reads one testssl.sh command line per line from <fname>.
                                   Can be combined with --serial or --parallel. Implicitly turns on "--warnings batch".
                                   Text format 1: Comments via # allowed, EOF signals end of <fname>
                                   Text format 2: nmap output in greppable format (-oG), 1 port per line allowed
     --mode <serial|parallel>      Mass testing to be done serial (default) or parallel (--parallel is shortcut for the latter)
     --warnings <batch|off>        "batch" doesnt continue when a testing error is encountered, off continues and skips warnings
     --connect-timeout <seconds>   useful to avoid hangers. Max <seconds> to wait for the TCP socket connect to return
     --openssl-timeout <seconds>   useful to avoid hangers. Max <seconds> to wait before openssl connect will be terminated

single check as <options>  ("testssl.sh URI" does everything except -E and -g):
     -e, --each-cipher             checks each local cipher remotely
     -E, --cipher-per-proto        checks those per protocol
     -s, --std, --standard         tests certain lists of cipher suites by strength
     -f, --fs, --nsa               checks forward secrecy settings
     -p, --protocols               checks TLS/SSL protocols (including SPDY/HTTP2)
     -g, --grease                  tests several server implementation bugs like GREASE and size limitations
     -S, --server-defaults         displays the servers default picks and certificate info
     -P, --server-preference       displays the servers picks: protocol+cipher
     -x, --single-cipher <pattern> tests matched <pattern> of ciphers
                                   (if <pattern> not a number: word match)
     -c, --client-simulation       test client simulations, see which client negotiates with cipher and protocol
     -h, --header, --headers       tests HSTS, HPKP, server/app banner, security headers, cookie, reverse proxy, IPv4 address

     -U, --vulnerable              tests all (of the following) vulnerabilities (if applicable)
     -H, --heartbleed              tests for Heartbleed vulnerability
     -I, --ccs, --ccs-injection    tests for CCS injection vulnerability
     -T, --ticketbleed             tests for Ticketbleed vulnerability in BigIP loadbalancers
     --BB, --robot                 tests for Return of Bleichenbachers Oracle Threat (ROBOT) vulnerability
     --SI, --starttls-injection    tests for STARTTLS injection issues
     -R, --renegotiation           tests for renegotiation vulnerabilities
     -C, --compression, --crime    tests for CRIME vulnerability (TLS compression issue)
     -B, --breach                  tests for BREACH vulnerability (HTTP compression issue)
     -O, --poodle                  tests for POODLE (SSL) vulnerability
     -Z, --tls-fallback            checks TLS_FALLBACK_SCSV mitigation
     -W, --sweet32                 tests 64 bit block ciphers (3DES, RC2 and IDEA): SWEET32 vulnerability
     -A, --beast                   tests for BEAST vulnerability
     -L, --lucky13                 tests for LUCKY13
     -WS, --winshock               tests for winshock vulnerability
     -F, --freak                   tests for FREAK vulnerability
     -J, --logjam                  tests for LOGJAM vulnerability
     -D, --drown                   tests for DROWN vulnerability
     -4, --rc4, --appelbaum        which RC4 ciphers are being offered?

tuning / connect options (most also can be preset via environment variables):
     --fast                        omits some checks: using openssl for all ciphers (-e), show only first preferred cipher.
     -9, --full                    includes tests for implementation bugs and cipher per protocol (could disappear)
     --bugs                        enables the "-bugs" option of s_client, needed e.g. for some buggy F5s
     --assume-http                 if protocol check fails it assumes HTTP protocol and enforces HTTP checks
     --ssl-native                  fallback to checks with OpenSSL where sockets are normally used
     --openssl <PATH>              use this openssl binary (default: look in $PATH, $RUN_DIR of testssl.sh)
     --proxy <host:port|auto>      (experimental) proxy connects via <host:port>, auto: values from $env ($http(s)_proxy)
     -6                            also use IPv6. Works only with supporting OpenSSL version and IPv6 connectivity
     --ip <ip>                     a) tests the supplied <ip> v4 or v6 address instead of resolving host(s) in URI
                                   b) arg "one" means: just test the first DNS returns (useful for multiple IPs)
     -n, --nodns <min|none>        if "none": do not try any DNS lookups, "min" queries A, AAAA and MX records
     --sneaky                      leave less traces in target logs: user agent, referer
     --user-agent <user agent>     set a custom user agent instead of the standard user agent
     --ids-friendly                skips a few vulnerability checks which may cause IDSs to block the scanning IP
     --phone-out                   allow to contact external servers for CRL download and querying OCSP responder
     --add-ca <CA files|CA dir>    path to <CAdir> with *.pem or a comma separated list of CA files to include in trust check
     --basicauth <user:pass>       provide HTTP basic auth information.
     --reqheader <header>          add custom http request headers

output options (can also be preset via environment variables):
     --quiet                       dont output the banner. By doing this you acknowledge usage terms normally appearing in the banner
     --wide                        wide output for tests like RC4, BEAST. FS also with hexcode, kx, strength, RFC name
     --show-each                   for wide outputs: display all ciphers tested -- not only succeeded ones
     --mapping <openssl|           openssl: use the OpenSSL cipher suite name as the primary name cipher suite name form (default)
                iana|rfc             -> use the IANA/(RFC) cipher suite name as the primary name cipher suite name form
                no-openssl|          -> dont display the OpenSSL cipher suite name, display IANA/(RFC) names only
                no-iana|no-rfc>      -> dont display the IANA/(RFC) cipher suite name, display OpenSSL names only
     --color <0|1|2|3>             0: no escape or other codes,  1: b/w escape codes,  2: color (default), 3: extra color (color all ciphers)
     --colorblind                  swap green and blue in the output
     --debug <0-6>                 1: screen output normal but keeps debug output in /tmp/.  2-6: see "grep -A 5 ^DEBUG= testssl.sh"
     --disable-rating              Explicitly disables the rating output

file output options (can also be preset via environment variables)
     --log, --logging              logs stdout to ${NODE}-p${port}${YYYYMMDD-HHMM}.log in current working directory (cwd)
     --logfile|-oL <logfile>       logs stdout to dir/${NODE}-p${port}${YYYYMMDD-HHMM}.log. If logfile is a dir or to a specified logfile
     --json                        additional output of findings to flat JSON file ${NODE}-p${port}${YYYYMMDD-HHMM}.json in cwd
     --jsonfile|-oj <jsonfile>     additional output to the specified flat JSON file or directory, similar to --logfile
     --json-pretty                 additional JSON structured output of findings to a file ${NODE}-p${port}${YYYYMMDD-HHMM}.json in cwd
     --jsonfile-pretty|-oJ <jsonfile>  additional JSON structured output to the specified file or directory, similar to --logfile
     --csv                         additional output of findings to CSV file ${NODE}-p${port}${YYYYMMDD-HHMM}.csv in cwd or directory
     --csvfile|-oC <csvfile>       additional output as CSV to the specified file or directory, similar to --logfile
     --html                        additional output as HTML to file ${NODE}-p${port}${YYYYMMDD-HHMM}.html
     --htmlfile|-oH <htmlfile>     additional output as HTML to the specified file or directory, similar to --logfile
     --out(f,F)ile|-oa/-oA <fname> log to a LOG,JSON,CSV,HTML file (see nmap). -oA/-oa: pretty/flat JSON.
                                   "auto" uses ${NODE}-p${port}${YYYYMMDD-HHMM}. If fname if a dir uses dir/${NODE}-p${port}${YYYYMMDD-HHMM}
     --hints                       additional hints to findings
     --severity <severity>         severities with lower level will be filtered for CSV+JSON, possible values <LOW|MEDIUM|HIGH|CRITICAL>
     --append                      if (non-empty) <logfile>, <csvfile>, <jsonfile> or <htmlfile> exists, append to file. Omits any header
     --overwrite                   if <logfile>, <csvfile>, <jsonfile> or <htmlfile> exists it overwrites it without any warning
     --outprefix <fname_prefix>    before  ${NODE}. above prepend <fname_prefix>


Options requiring a value can also be called with = e.g. testssl.sh -t=smtp --wide --openssl=/usr/bin/openssl <URI>.
<URI> always needs to be the last parameter.

パラメータのURIについては、「example.com:8080」みたいにすればポート指定が可能。

この辺りを使用して、こんな感じで実行してみる。

./testssl.sh --html example.com:8080
./testssl.sh --log example.com:8080

htmlオプションは結果をHTMLで記録してくれるので、Linuxで実行した結果をWindowsで見たいといった場合に使いやすい。

logオプションは結果をbashの装飾機能を使って色付けしてくれるので、bashコンソール上で再確認するといった場合は使いやすい。

ただし、Windowsでログファイルを見る場合は、タグに制御コードを使用しているため、見辛くくなってしまう。

なお、htmlオプションやlogオプションの有無に関わらず実行結果はコンソールに標準出力される。

実行結果

やってみた結果はこんな感じ(一部抜粋)

###########################################################
    testssl.sh       3.1dev from [https://testssl.sh/dev/](https://testssl.sh/dev/)
 (895a6b9 2021-03-11 10:42:52 -- )
 This program is free software. Distribution and
             modification under GPLv2 permitted.
      USAGE w/o ANY WARRANTY. USE IT AT YOUR OWN RISK!

       Please file bugs @ [https://testssl.sh/bugs/](https://testssl.sh/bugs/)
 ###########################################################

 Using "OpenSSL 1.0.2-chacha (1.0.2k-dev)" \[~183 ciphers\]
 on ik1-419-41682:./bin/openssl.Linux.x86\_64
 (built: "Jan 18 17:12:17 2019", platform: "linux-x86\_64")

 Start 2021-03-20 22:07:04        -->> 100.100.100.100:8080 (example.com) <<--

 rDNS (100.100.100.100):  example.com.
 Service detected:       HTTP

 Testing protocols via sockets except NPN+ALPN 

 SSLv2 not offered (OK)
 SSLv3 not offered (OK)
 TLS 1 not offered
 TLS 1.1 not offered
 TLS 1.2 offered (OK)
 TLS 1.3 not offered and downgraded to a weaker protocol
 NPN/SPDY not offered
 ALPN/HTTP2 not offered

 Testing cipher categories 

 NULL ciphers (no encryption) not offered (OK)
 Anonymous NULL Ciphers (no authentication) not offered (OK)
 Export ciphers (w/o ADH+NULL) not offered (OK)
 LOW: 64 Bit + DES, RC\[2,4\], MD5 (w/o export) not offered (OK)
 Triple DES Ciphers / IDEA not offered
 Obsoleted CBC ciphers (AES, ARIA etc.) offered
 Strong encryption (AEAD ciphers) with no FS offered (OK)
 Forward Secrecy strong encryption (AEAD ciphers) offered (OK)

 Testing server's cipher preferences 

 Has server cipher order? no (NOT ok)
 Negotiated protocol TLSv1.2
 Negotiated cipher AES128-GCM-SHA256 -- inconclusive test, matching cipher in list missing, better see below
 Cipher per protocol

Hexcode  Cipher Suite Name (OpenSSL)       KeyExch.   Encryption  Bits     Cipher Suite Name (IANA/RFC)
-----------------------------------------------------------------------------------------------------------------------------
SSLv2
 - 
SSLv3
 - 
TLSv1
 - 
TLSv1.1
 - 
TLSv1.2 (no server order, thus listed by strength)
 xc030   ECDHE-RSA-AES256-GCM-SHA384       ECDH 521   AESGCM      256      TLS\_ECDHE\_RSA\_WITH\_AES\_256\_GCM\_SHA384              
 xc028   ECDHE-RSA-AES256-SHA384           ECDH 521   AES         256      TLS\_ECDHE\_RSA\_WITH\_AES\_256\_CBC\_SHA384              
 xc014   ECDHE-RSA-AES256-SHA              ECDH 521   AES         256      TLS\_ECDHE\_RSA\_WITH\_AES\_256\_CBC\_SHA                 
 xcca8   ECDHE-RSA-CHACHA20-POLY1305       ECDH 521   ChaCha20    256      TLS\_ECDHE\_RSA\_WITH\_CHACHA20\_POLY1305\_SHA256        
 xc077   ECDHE-RSA-CAMELLIA256-SHA384      ECDH 521   Camellia    256      TLS\_ECDHE\_RSA\_WITH\_CAMELLIA\_256\_CBC\_SHA384         
 x9d     AES256-GCM-SHA384                 RSA        AESGCM      256      TLS\_RSA\_WITH\_AES\_256\_GCM\_SHA384                    

 Testing vulnerabilities 

 Heartbleed (CVE-2014-0160)                not vulnerable (OK), no heartbeat extension
 CCS (CVE-2014-0224)                       not vulnerable (OK)
 Ticketbleed (CVE-2016-9244), experiment.  not vulnerable (OK)
 ROBOT not vulnerable (OK)
 Secure Renegotiation (RFC 5746) supported (OK)
 Secure Client-Initiated Renegotiation VULNERABLE (NOT ok), DoS threat (6 attempts)
 CRIME, TLS (CVE-2012-4929)                not vulnerable (OK)
 BREACH (CVE-2013-3587)                    no gzip/deflate/compress/br HTTP compression (OK)  - only supplied "/" tested
 POODLE, SSL (CVE-2014-3566)               not vulnerable (OK), no SSLv3 support
 TLS\_FALLBACK\_SCSV (RFC 7507)              No fallback possible (OK), no protocol below TLS 1.2 offered
 SWEET32 (CVE-2016-2183, CVE-2016-6329)    not vulnerable (OK)
 FREAK (CVE-2015-0204)                     not vulnerable (OK)
 DROWN (CVE-2016-0800, CVE-2016-0703)      not vulnerable on this host and port (OK)
                                           make sure you don't use this certificate elsewhere with SSLv2 enabled services
                                           https://censys.io/ipv4?q=2DA7122DD4B5E469076E1331612447F67B73AA399AA7388775C717ED5BD07725 could help you to find out
 LOGJAM (CVE-2015-4000), experimental      not vulnerable (OK): no DH EXPORT ciphers, no DH key detected with <= TLS 1.2
 BEAST (CVE-2011-3389)                     not vulnerable (OK), no SSL3 or TLS1
 LUCKY13 (CVE-2013-0169), experimental     potentially VULNERABLE, uses cipher block chaining (CBC) ciphers with TLS. Check patches
 Winshock (CVE-2014-6321), experimental    not vulnerable (OK) - ARIA, CHACHA or CCM ciphers found
 RC4 (CVE-2013-2566, CVE-2015-2808)        no RC4 ciphers detected (OK)

 Running client simulations (HTTP) via sockets 

 Rating specs (not complete)  SSL Labs's 'SSL Server Rating Guide' (version 2009q from 2020-01-30)
 Specification documentation [https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide](https://github.com/ssllabs/research/wiki/SSL-Server-Rating-Guide)
 Protocol Support (weighted)  100 (30)
 Key Exchange    (weighted)  90 (27)
 Cipher Strength (weighted)  90 (36)
 Final Score 93
 Overall Grade A
 Grade cap reasons Grade capped to A. HSTS is not offered

 Done 2021-03-20 22:09:14 \[ 132s\] -->> 100.100.100.100:8080 (example.com) <<--

testssl結果

Overall GradeはAだったので、概ねは問題ないのだが、以下の点が気になった。

Secure Client-Initiated Renegotiation VULNERABLE (NOT ok), DoS threat (6 attempts)

Qiita # testssl.sh の Secure Client-Initiated Renegotiation チェック

ここを見てみると、CVE-2011-1473の対応が出来ていないということらしい。

stone修正

脆弱性に対応するには、自分のサーバ構成上どうしてもstoneを修正する必要がある。

現在の設定オプションを見てみると、SSLフラグに関する設定は後付けできないので、ソースを修正することにする。

stoneでCTXオプションを設定している箇所があるので、そこに1行追加する。

    SSL_CTX_set_options(ss->ctx, opts->off);
    ↓
    SSL_CTX_set_options(ss->ctx, opts->off);
    SSL_CTX_set_options(ss->ctx, SSL_OP_NO_RENEGOTIATION);

SSL_CTX_set_optionsではビットマスクを使用してオプションを追加して、複数セットしたとしてもクリアされない。

ということで、修正したソースを使用してmakeしたものに入れ替えて改めてtestssl.shを実行すると、Secure Client-Initiated Renegotiationの部分が「not vulnerable (OK)」となったので、対応は完了。

リバースプロキシが使用しているcipher suiteの対処をした

ちゃんとしたSSL化をしてみる

今回の経緯と目的

現状としてGoogle Chrome等で検証を行ってみると、encrypt自体はされているものの状態として望ましくない感じっていうことが実はあった。 f:id:neji_shiki:20210312153927p:plain

これに対応するためにオプションにOpenSSL 1.0.2で使用できるcipher suiteの指定をしてみたが、起動してもエラーとなって使えない状況となっていた。

そのためOpenSSL 1.1.1を使えるようにすることで、ここら辺を打開できるか試してみようっていう試み。

サーバの状態

現状として、使用しているサーバーはCentOS7で、CentOS7のOpenSSLはバージョンが古い(サポート期限なんてとっくに切れている)。

使用しているCentOSとOpenSSLのバージョンはこんな感じ。

OpenSSLのバージョンを調べると、2019年12月31日にサポート期限が切れているのがわかる。

$ cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

$ openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017

stoneをmakeするためにopenssl-develパッケージをインストールしていたけど、これも1.0.2となっている。

$ sudo yum info openssl-devel
インストール済みパッケージ
名前                : openssl-devel
アーキテクチャー    : x86_64
エポック            : 1
バージョン          : 1.0.2k
リリース            : 21.el7_9
容量                : 3.1 M
リポジトリー        : installed
提供元リポジトリー  : updates
要約                : Files for development of applications which will use OpenSSL
URL                 : http://www.openssl.org/
ライセンス          : OpenSSL
説明                : OpenSSL is a toolkit for supporting cryptography. The openssl-devel
                    : package contains include files needed to develop applications which
                    : support various cryptographic algorithms and protocols.

OpenSSL 1.1.1をインストール

適当に見た感じでは、OpenSSL 1.1.1では openssl-devel 1.0.2に含まれるヘッダーファイルが含まれているっぽい。

とはいえ、CentOS7にOpenSSL 1.1.1をインストールする場合はソースから行う必要があるみたいなので、システム全体じゃなくて作業用のユーザーのみ入れ替えを行う感じでインストールを行う。

リポジトリパスを追加すればyumとかのコマンドで行けたかもしれないけど、詳しくは見ていない。

参考 : とりあえずこの辺り

 # CentOS7にOpenSSL1.1.1をインストール

 CentOS 7.6 にソースコードから OpenSSL 1.1.1c をインストールする - らくがきちょう

インストールが終わると、OpenSSL 1.1.1が使用可能になったことがわかる。

ただし、root等の別ユーザーやシステムとしてはOpenSSL 1.0.2を使用している状態となっている。

$ openssl version
OpenSSL 1.1.1j  16 Feb 2021

$ sudo openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017

stoneのmakeやり直し

Makefile編集

stoneのMakefileを編集して、インストールしたOpenSSL 1.1.1をとりあえず使用するように変更する。

きれいな編集はしていないけど、編集内容はこんな感じ。

Makefile内に使用するopensslコマンドのパスを変更して、SSL_LIBSについてもlibディレクトリのパスを追加している。

linuxタグのオプションについては不要かと思ったけど、「-D_GNU_SOURCE」を追加している。

23c23
<
< SSL=          /usr/local/ssl
---
> SSL=          /usr/local/openssl/bin/
26c27
< SSL_LIBS=     -lssl -lcrypto
---
> SSL_LIBS=     -L/usr/local/openssl/lib/ -lssl -lcrypto
99c100
<       $(MAKE) FLAGS="-O -Wall -DCPP='\"/usr/bin/cpp -traditional\"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_EPOLL $(FLAGS)" LIBS="-lpthread $(LIBS)" stone
---
>       $(MAKE) FLAGS="-O -Wall -DCPP='\"/usr/bin/cpp -traditional\"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 $(SSL_FLAGS) -DUSE_EPOLL -D_GNU_SOURCE $(FLAGS)" LIBS="-lpthread $(LIBS)" stone

stone.c編集

stone.cについてもOpenSSL 1.1.1を使用するために修正が必要となる。

 参考tcpリピータのstone - 極限環境材料化学研究室

ここにある通り、stone.c内のSSL_state()をSSL_get_state()に置き換えを行う。

make実行

makeを行うと、OpenSSL 1.0.2からOpenSSL 1.1.1を使用することに変更したために以下のような警告が発生する。 とりあえず警告自体は無視することにした。

makeを実行する前にOpenSSL 1.1.1のための環境変数も設定する。

$ export C_INCLUDE_PATH=/usr/local/openssl/include/
$ make linux-ssl
make TARGET=linux ssl_stone LIBS="-ldl"
make[1]: ディレクトリ `/Local/stone' に入ります
make FLAGS="-DUSE_POP -DUSE_SSL -DCONST_SSL_METHOD -DOPENSSL_NO_TLS1 -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 " LIBS="-ldl -L/usr/local/openssl/lib/ -lssl -lcrypto" linux
make[2]: ディレクトリ `/Local/stone' に入ります
make FLAGS="-O -Wall -DCPP='\"/usr/bin/cpp -traditional\"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_SSL -DCONST_SSL_METHOD -DOPENSSL_NO_TLS1 -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -DUSE_EPOLL -D_GNU_SOURCE -DUSE_POP -DUSE_SSL -DCONST_SSL_METHOD -DOPENSSL_NO_TLS1 -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 " LIBS="-lpthread -ldl -L/usr/local/openssl/lib/ -lssl -lcrypto" stone
make[3]: ディレクトリ `/Local/stone' に入ります
cc -D_GNU_SOURCE  -O -Wall -DCPP='"/usr/bin/cpp -traditional"' -DPTHREAD -DUNIX_DAEMON -DPRCTL -DSO_ORIGINAL_DST=80 -DUSE_SSL -DCONST_SSL_METHOD -DOPENSSL_NO_TLS1 -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3 -DUSE_EPOLL -D_GNU_SOURCE -DUSE_POP -DUSE_SSL -DCONST_SSL_METHOD -DOPENSSL_NO_TLS1 -DOPENSSL_NO_SSL2 -DOPENSSL_NO_SSL3  -o stone stone.c -lpthread -ldl -L/usr/local/openssl/lib/ -lssl -lcrypto
stone.c: 関数 ‘asyncHealthCheck’ 内:
stone.c:2087:5: 警告: ‘ERR_remove_state’ は廃止されました (宣言位置 /usr/local/openssl/include/openssl/err.h:261) [-Wdeprecated-declarations]
     ASYNC_END;
     ^
stone.c: 関数 ‘asyncConn’ 内:
stone.c:4228:5: 警告: ‘ERR_remove_state’ は廃止されました (宣言位置 /usr/local/openssl/include/openssl/err.h:261) [-Wdeprecated-declarations]
     ASYNC_END;
     ^
stone.c: 関数 ‘asyncAcceptConnect’ 内:
stone.c:7123:5: 警告: ‘ERR_remove_state’ は廃止されました (宣言位置 /usr/local/openssl/include/openssl/err.h:261) [-Wdeprecated-declarations]
     ASYNC_END;
     ^
stone.c: 関数 ‘repeater’ 内:
stone.c:8067:5: 警告: ‘ERR_remove_state’ は廃止されました (宣言位置 /usr/local/openssl/include/openssl/err.h:261) [-Wdeprecated-declarations]
     ERR_remove_state(0);
     ^
stone.c: 関数 ‘sslopts’ 内:
stone.c:9355:2: 警告: ‘TLSv1_2_server_method’ は廃止されました (宣言位置 /usr/local/openssl/include/openssl/ssl.h:1890) [-Wdeprecated-declarations]
  if (isserver) opts->meth = TLSv1_2_server_method();
  ^
stone.c:9356:2: 警告: ‘TLSv1_2_client_method’ は廃止されました (宣言位置 /usr/local/openssl/include/openssl/ssl.h:1891) [-Wdeprecated-declarations]
  else opts->meth = TLSv1_2_client_method();
  ^
stone.c:9360:2: 警告: ‘TLSv1_1_server_method’ は廃止されました (宣言位置 /usr/local/openssl/include/openssl/ssl.h:1884) [-Wdeprecated-declarations]
  if (isserver) opts->meth = TLSv1_1_server_method();
  ^
stone.c:9361:2: 警告: ‘TLSv1_1_client_method’ は廃止されました (宣言位置 /usr/local/openssl/include/openssl/ssl.h:1885) [-Wdeprecated-declarations]
  else opts->meth = TLSv1_1_client_method();
  ^
make[3]: ディレクトリ `/Local/stone' から出ます
make[2]: ディレクトリ `/Local/stone' から出ます
make[1]: ディレクトリ `/Local/stone' から出ます

makeしたstoneの確認

依存している共有ライブラリの確認

lddコマンドを使用してライブラリにopenssl1.1.1のものが含まれているかを確認。 以下の例だと「libssl.so.1.1」「libcrypto.so.1.1」がopenssl1.1.1のもの。

 ldd ./stone
        linux-vdso.so.1 =>  (0x00007ffd6ed8c000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f95bfde1000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f95bfbdd000)
        libssl.so.1.1 => /usr/local/openssl/lib/libssl.so.1.1 (0x00007f95bf94b000)
        libcrypto.so.1.1 => /usr/local/openssl/lib/libcrypto.so.1.1 (0x00007f95bf45f000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f95bf091000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f95bfffd000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f95bee7b000)

起動確認

新しいバイナリで同じようにリバースプロキシを立ち上げた場合に使用されるcipher suiteを確認。

こんな感じでConnectionの項目が変わっている。 f:id:neji_shiki:20210312153932p:plain

ということで、TLS 1.2で怒られない感じのcipher suiteを使用したリバースプロキシの立ち上げにはこれで成功した感じ。

とはいえ、NginxとかApacheをおとなしく使うほうが導入の手間は少ないと思う。

Docker使えばすぐに立ち上がるしね。

WebサーバのSSL化対応

■WebサーバのSSL

keitaircのSSL化を棚上げしていたものをようやくやったので、その話。

■Reverse Proxy(トンネリング)の構築に向けて

keitaircのssl化はマニュアルにある通り、mod_ssl等を利用することを想定している。
keitairc自体はApacheやNGINXに代表されるようなHTTPサーバ上で動いているわけじゃなく、keitairc自身が簡易サーバとして動作しているため、わざわざmod_sslモジュールを使うためだけにApacheを立ち上げるのもめんどくさい。
そこで、NGINXなどでReverse Proxyを立ち上げてトンネリングすることで、サーバの外はhttpsで動作し、サーバ内は今まで通りhttpで動作させることにした。

イメージとしてのReverse Proxyの導入イメージはこんな感じ。
HTTPS<-->HTTPをReverse Proxyで繋ぐ。
HTTPSの処理はReverse Proxyにて行うため、HTTPより奥では処理に変更がないことになる。

            +--------------------------------------+
            |Server                                |
            |+---------+  +----------+  +--------+||
            || Reverse |  | keitairc |  | tiarra |||
Inter Net --||  Proxy  |--|  (HTTP)  |--| (TCP)  |||
            || (HTTPS) |  |          |  |        |||
            |+---------+  +----------+  +--------+||
            +--------------------------------------+

■いろいろな選択肢

■選択肢 Apacheを使う(mod_proxy/mod_ssl)

Apacheのモジュールとして動作するため、基本的にApache+(mod_proxy or/and mod_ssl)として動作させる。 現状ではhttpdが必要な用途がReverse Proxyのみのため、正直面倒。

■選択肢 NGINXを使う

静的HTMLコンテンツの配信に長けているhttpdの一種。 一応モジュールの追加でCGIも動作させることもできるらしい。 とはいえ、Apache同様にhttpdが必要な用途がReverse Proxyのみのため、面倒なことに変わりはない。

■選択肢 other

■gost

go言語で書かれたgostっていう多機能プロトコル変換中継simple tunnelソフトウェアらしい。
# gost - GO Simple Tunnel がすごい

■stone

c言語で書かれたアプリケーションレベルの TCP & UDP リピーター。 ## Simple Repeater

■用途として一番しっくり来たstoneを使用する

sourceをDLしてmakeしないといけないのだが、だいたいeldorado-of.infoのWiki/stoneの通りにコマンドを打ち込むだけで苦も無く実行可能バイナリが出来上がる。
ただし、使用しているバージョンは正式版ではあるが、2008-02-05にリリースされたバージョンでもあるので、ここが厄介。
ということで、stoneのCVSを覗いてみるとOpenSSL 1.1.1に対応したソースが公開されているので、wgetコマンドにCVSのtarballリンクアドレスを指定して、ソースをまとめてダウンロードして使用する。
このバージョンだと先の説明にあったようなmakefileの書き換えや、ワーニング等は発生しなかった。

■stoneのmake完了後の動作確認

makeが終わったら動作確認のために適当に起動をしてみる。
以下例はstoneを外側ポート1000で待ち受けて、内側ポート1100とつなぐという感じ。
これで動作が確認出来たらひとまずよしとする。

stone localhost:1000 1100

SSLサーバ証明書

Webサーバをhttps化するにあたって、SSLサーバ証明書が必要になる。
いろいろ発行機関はあるが、個人利用であるためLet’s Encryptを使用することにした。

Let’s Encryptでの証明書発行準備

certbot導入

Let’s Encryptの証明書発行においては、ホームページに記載のある通りcertbotを導入する方向にした。
参考サイトを見つつこれもインストールと証明書の発行を行っていく。
 # CentOS7】Lets EncryptでSSL証明書を取得

■証明書自動更新設定

Let's Encryptの証明書については、期限が3か月なので、自動更新の設定も併せて実施する。
とりあえずは証明書更新コマンドの確認をしてみる。

sudo certbot renew --dry-run

コマンドが正常に動作することを確認したら、cronに設定を追加する。 証明書更新は1か月を切ったら新しいのが発行できるらしいのと、証明書更新コマンド自体は実行して空振りに終わるか更新できるかなので、月1回実行する形の例。 これで毎月1日の0時0分に実行される形になる。

00 00 01  *  * sudo /usr/bin/certbot renew

■stone起動設定

confファイルを使用することでコマンドラインオプションを定義ファイルとして保存できるので、起動条件を変更する場合も簡単になる。

■定義ファイル作成

以下は証明書と秘密鍵の指定とTLS1.2の指定、HTTP<->HTTPSのトンネルを行うポート設定を指定する。
他の指定は用途毎に指定する。

-z key=/etc/letsencrypt/live/example.com/privkey.pem
-z cert=/etc/letsencrypt/live/example.com/cert.pem
-z verify,none
-z CApath=/etc/letsencrypt/live/example.com
-z tls1.2
stone localhost:1000 1100/ssl

■stone起動確認

証明書を起動時に読み込む必要があるので、証明書のシンボリックリンク等を専用の場所に作成するか、certbotに合わせてrootで起動してみる。
これでstoneの起動が確認できたらブラウザアクセスをして接続できることを確認する。

nohup sudo /usr/local/bin/stone -C target_conf &

■起動用シェル

stone起動用に以下のシェルを作成。
サーバリブート時の起動と、証明書更新時の自動再起動を想定した再起動を行うために最低限必要なことだけを行っている。
プロセスを再起動するため、ポート開放の可能性を考えて適当に10秒スリープさせている。

#!/bin/bash -l
cd /Local/stone_home

## Kill
if [ `ps -ef | egrep "stone.+conf" | egrep -v "grep|sudo|bash" | wc -l` -ne 0 ]; then
        for stone_proc in `ps -ef| egrep "stone.+conf" | egrep -v "grep|sudo|bash" | awk '{print $2}'`
        do
                sudo kill -9 $stone_proc
        done
fi

sleep 10

## Start
for target_conf in `ls stone*.conf`
do
        if [ `ps -ef | egrep $target_conf | egrep -v "grep|sudo|bash" | wc -l` -eq 0 ]; then
                nohup sudo /usr/local/bin/stone -C $target_conf 1>/dev/null 2>&1 &
        fi
done

このシェルをサーバ起動時及び、certbot起動後に動作するようにcronを設定して終わり。

@reboot /Local/stone_run.bash 1>/dev/null 2>&1 &
00 00 01  *  * sudo /usr/bin/certbot renew && /Local/stone_run.bash 1>/dev/null 2>&1 &

メモ用にWikiを構築しようとした話

メモの溜め込みにWikiを使おうって思った

VPS立てた後に使おうかなって考えてたものにWikiがある。
特に目新しいことをやろうとか、大仰なことをやろうとかいうのではなくて、メモの書き留めに使いたいって理由。
Google KeepとかMicorosoft ONENOTEとか、今の時代となっては自動的にバックアップと同期までしてくれるツールがあふれているので、急いではいなかった。

昔の環境と今の事情

当時はZaurus(たぶんSL-C3000)でw3mを使用してその中のローカルCGI機能を使ってWiki(RandomNote)を動かしていたんだけど、今となってはスマホがあるし、通信量は気にするほどでもないし、サーバーがあるからそれを使えばいいよねっていう感じ。

ちなみに昔使っていた時は新しいWikiクローンがどんどん生まれていた気がするけど、10年も経つとどんどん減っているみたいで、当時使っていたRandomNoteしかり、なかなか使えそうなWikiクローンが見つからなかった。
用途としてはメモとしての機能に重点を置いているので、動作がシンプルであればあるほどいいぐらい。

とりあえずの候補

Scrapmemo

昔使っていたRandomNoteの構想に近いことから候補にした。
だーっと書いたものをすべてテキストファイルとして管理してくれるので、ファイル管理もサーバー管理も楽そう。

Konawiki3

これもDBではなくて、テキストファイルにデータを書き込むやつ。
Konawiki2はDBを使うのと機能も豊富らしいけど、データの取り扱いが楽なのがよさそう。

Hiki

アクセス制限やユーザ管理が行えるので、インターネット上での個人用という用途に向く。

# FreeStyleWiki

昔関わっていたプロジェクトで情報共有のために建てた気がする。

mono

RandomNoteの作者によるもの。
記法もないので、書き溜めるだけ書き溜める用途には向く。

PukiWiki

Yukiwikiがなくなっていたので、こっちもなくなっているかと思ったぐらいの古参。
むしろメンテナンスもされているようで、安定して使えることができそう。

とりあえずの候補(番外編)

番外編として、ローカル環境(パソコン上)で同じような使い方ができるものについて考えてみる。

ひとりWiki

定番中の定番(だと思う)。
これ1つで導入が終わるので、環境のことなんて考えなくていいっていうのはすごい。

Obsidian

ノートの取り方であるZettelkasten(gigazine内記事)について調べていたところ見つけたやつ。
発想としてはひとりWikiにかなり似通っている。
Zettelkastenの実践で真価を発揮しそう。

今のところの決着

ひとまずはObsidianでMarkdownファイルを扱いつつ、Zettelkastenをやってみることにした。
Webサーバの構築とかファイアウォール設定もあるしなーってめんどくさくなってきたので、楽なほうに転んだ。
そのうちちゃんと考えるかも。

SSHクライアントとしてのVS Code

TeratermじゃなくてVS Codeで直接いじれる環境も作ろうかなっと

だいたいTerminalソフトとしてはTeraTermを愛用しているわけだけど、せっかくVS Codeもあるし、VS CodeSSH開発環境も整えようというあれこれ。

接続できない問題

とはいえ、2台目の構築だったのでそんなに手間取ることもないだろうなって思ったら、こんな感じのエラーが出てうまくいかなかった。

[xx:xx:xx.xxx] Log Level: 2
[xx:xx:xx.xxx] remote-ssh@0.63.0
[xx:xx:xx.xxx] win32 x64
[xx:xx:xx.xxx] SSH Resolver called for "ssh-remote+hogehoge.hogehoge", attempt 1
[xx:xx:xx.xxx] "remote.SSH.useLocalServer": false
[xx:xx:xx.xxx] "remote.SSH.showLoginTerminal": false
[xx:xx:xx.xxx] "remote.SSH.remotePlatform": {}
[xx:xx:xx.xxx] "remote.SSH.sshPath": undefined
[xx:xx:xx.xxx] "remote.SSH.sshConfigurationFile": undefined
[xx:xx:xx.xxx] "remote.SSH.useFlock": true
[xx:xx:xx.xxx] "remote.SSH.lockfilesInTmp": false
[xx:xx:xx.xxx] "remote.SSH.localServerDownload": auto
[xx:xx:xx.xxx] "remote.SSH.remoteServerListenOnSocket": false
[xx:xx:xx.xxx] "remote.SSH.showLoginTerminal": false
[xx:xx:xx.xxx] SSH Resolver called for host: hogehoge.hogehoge
[xx:xx:xx.xxx] Setting up SSH remote "hogehoge.hogehoge"
[xx:xx:xx.xxx] Using commit id "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" and quality "stable" for server
[xx:xx:xx.xxx] Install and start server if needed
[xx:xx:xx.xxx] Checking ssh with "ssh -V"
[xx:xx:xx.xxx] > OpenSSH_for_Windows_7.7p1, LibreSSL 2.6.5

[xx:xx:xx.xxx] Running script with connection command: ssh -T -D 65312 "hogehoge.hogehoge" bash
[xx:xx:xx.xxx] Terminal shell path: C:\Windows\System32\cmd.exe
[xx:xx:xx.xxx] > The authenticity of host '[hogehoge.hogehoge]:XXXX ([XXX.XXX.XXX.XXX]:XXXX)'
> can't be established.
> ECDSA key fingerprint is SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
> Are you sure you want to continue connecting (yes/no)?]0;C:\Windows\System32\cmd.exe
[xx:xx:xx.xxx] Got some output, clearing connection timeout
[xx:xx:xx.xxx] Detected fingerprint confirmation message
[xx:xx:xx.xxx] Showing fingerprint confirmation dialog
[xx:xx:xx.xxx] Got fingerprint response: yes
[xx:xx:xx.xxx] "install" wrote data to terminal: "yes"
[xx:xx:xx.xxx] > y
[xx:xx:xx.xxx] > Are you sure you want to continue connecting (yes/no)? yes
> Warning: Permanently added '[hogehoge.hogehoge]:XXXX,[XXX.XXX.XXX.XXX]:XXXX' 
> (ECDSA) to the list of known hosts.
[xx:xx:xx.xxx] > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
[xx:xx:xx.xxx] > @         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
> @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
> Permissions for 'XXXXXXXXXXXXXX//id_rsa' are too open.
> It is required that your private key files are NOT accessible by others.
> This private key will be ignored.
> Load key "XXXXXXXXXXXXXX//id_rsa": bad permissions
> XXXX@hogehoge.hogehoge: Permission denied (publickey).
> プロセスが、存在しないパイプに書き込もうとしました。
> 
[xx:xx:xx.xxx] "install" terminal command done
[xx:xx:xx.xxx] Install terminal quit with output: プロセスが、存在しないパイプに書き込もうとしました。
[xx:xx:xx.xxx] Received install output: プロセスが、存在しないパイプに書き込もうとしました。
[xx:xx:xx.xxx] Stopped parsing output early. Remaining text: プロセスが、存在しないパイプに書き込もうとしました。
[xx:xx:xx.xxx] Failed to parse remote port from server output
[xx:xx:xx.xxx] Resolver error: Error: 
	at Function.Create (c:\Users\user\.vscode\extensions\ms-vscode-remote.remote-ssh-0.63.0\out\extension.js:1:64027)
	at Object.t.handleInstallOutput (c:\Users\user\.vscode\extensions\ms-vscode-remote.remote-ssh-0.63.0\out\extension.js:1:62766)
	at k (c:\Users\user\.vscode\extensions\ms-vscode-remote.remote-ssh-0.63.0\out\extension.js:1:312915)
	at processTicksAndRejections (internal/process/task_queues.js:94:5)
	at async c:\Users\user\.vscode\extensions\ms-vscode-remote.remote-ssh-0.63.0\out\extension.js:1:310801
	at async Object.t.withShowDetailsEvent (c:\Users\user\.vscode\extensions\ms-vscode-remote.remote-ssh-0.63.0\out\extension.js:1:405790)
	at async Object.t.resolve (c:\Users\user\.vscode\extensions\ms-vscode-remote.remote-ssh-0.63.0\out\extension.js:1:314454)
	at async c:\Users\user\.vscode\extensions\ms-vscode-remote.remote-ssh-0.63.0\out\extension.js:127:110333
[xx:xx:xx.xxx] ------

見た感じPrivate Keyの権限問題だったんだけど、Private Key自体は開けるし、なんでだろうと思ってconfigファイルをC:\Users\ユーザ名/.ssh/configからC:\ProgramData\ssh\ssh_configに移動したりしたんだけど結局駄目だった。
というか、C:\ProgramData\ssh\ssh_configに至ってはVS Codeで編集したものが他のテキストエディタでは繁栄されていなかったり、その逆が起こったりでそういう意味でも使うのを躊躇する事象が発生した。

Windowsでファイル自体の権限情報触ったのっていつ以来だろう

結局のところ、Windowsではあまり使用しない権限情報を編集することで使用することができるようになった。
ここにたどり着かなかったら駄目だったかもしれない。
qiita.com

TerminalソフトとVS Codeのttyについて

TerminalソフトなんかでサーバOSに接続した場合、wとかwhoコマンドでセッション情報を確認することがよくあると思う。
個人だとそうはないかもしれないけど、チーム開発だとあるよね。

TeraTermなんかでももちろんそうで、Teratermを使用した場合のwhoコマンドの結果はこんな感じになる。

$ who
xxxxxx   pts/0        2021-01-31 16:54 (XXXXXXXXXXXXXXXXXXXXXXXXXXXX)

これに対して、VS Codeの場合はwとかwhoではセッション情報が帰ってこない。
(設定ちゃんとやればいいのかもしれないけど)
これに対してpsコマンドでログイン状態を見てみるとこういうことになっていた。

Teraterm
root      1432     1  0 16:54 ?        00:00:00 sshd: xxxxxx [priv]
xxxxxx    1434  1432  0 16:54 ?        00:00:00 sshd: xxxxxx@pts/0

VS Code
root      1603     1  0 17:05 ?        00:00:00 /usr/sbin/sshd -D
root      5324  1603  0 18:22 ?        00:00:00 sshd: xxxxxx [priv]
xxxxxx    5326  5324  0 18:22 ?        00:00:00 sshd: xxxxxx@notty

面白いのはTeratermではpts/0ということなので、仮想端末情報が割り当てられている。
それに対してVS Codeでは仮想端末情報が割り当てられていないため、nottyとなっていること。
ttyが割り当てられていないため、wやwhoで異なる結果となったというのは納得できるところ。

ログインシェルの種類によってはVS CodeのRemote-SSHが使用できないというのもあるらしいが、一応そういうこともないのでいいのかもしれない。