Foltia with AppleScript

Foltia animelockerのトラブルシューティング

SSHでのFoltiaサーバーへの接続

SSH (Secure SHell)です。コマンドラインでほとんどの全てのUnixのリモートコントロールが出来ます。 逆に言うと管理が甘いと完全に乗っ取られます。 通常はSSHでログインする時にはパスワードでの認証をして入りますが、特定の手順をとるとパスワードのやりとりを省いて接続することが出来ます。 

ApplescriptでリモートからFoltiaサーバーを監視する際に問題となるのはこのSSHをいかに簡単に単純に誤動作無く行うかという点にあります。 パスワードを対話形式で反応するのは遅くなりますし、プログラム上にパスワードを平文で記載しておかなくてはならなくなりセキュリティー的な問題も発生します。 なのでここはRSA認証でパスワード認証無しで Single Lineで Shellコマンドを実行出来る様にしておきましょう。 

末尾にTerminalを使って対話式に実行するアップルスクリプトのサンプルを添付しておきます。 これはこれでなかなかに良いもんです。

SSHでのFoltiaサーバーへの接続

皆さんお気づきだと思うのですが。 ssh foltia@foltia.local といったかんじでサーバーにアクセス使用とするとRSAキーを要求されます。

$ ssh foltia@foltia.local

Unable to negotiate with 192.168.1.5 port 22: no matching host key type found. Their offer: ssh-rsa,ssh-dss

とかそんな感じで帰って来ます。

これは以下の様に記載するととりあえずはssh接続が出来ます。

ssh foltia@foltia.local -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedKeyTypes=+ssh-rsa

ですがコマンドが長くなりすぎますし、この後実行するid_rsa.pub のサーバへのコピーの時に結構面倒になるので

~/.ssh/configを記載して複雑な接続手順を一括で保管しておくことが有効です。

.ssh/configをつかったrsa認証によるパスワード無し接続の設定

この方のリンクが参考になりました。

でも先ず御託は面倒なので実践して見ましょう。

1) local$ ssh-keygen

RSAキーを作成します。 いろいろ聞かれるけど、すべてエンターで対応する。 id_rsa.pubというファイルが出来ている。 この際 ~/.ssh/フォルダが作成されています。

2) local$ touch ~/.ssh/config

これでconfigファイルの空ファイルが出来ます。 その後

vim ~/.ssh/config  ☆で記載開始☆

i  ☆で記入開始できます。☆

Host foltia.local
    Hostname foltia.local
    User foltia
    AddressFamily inet
    HostKeyAlgorithms ssh-rsa
    PubkeyAcceptedKeyTypes +ssh-rsa

☆escapeして :qwで記入完了

3) local$  scp ~/.ssh/id_rsa.pub foltia@foltia.local:  

これで公開キーをサーバーにコピー出来る。 最後のコロンが大事

4) リモートホストにログインし、authorized_keys ファイルを生成

local$ ssh foltia@foltia.local
remort$ mkdir .ssh
    #あれば不要
remort$ chmod 700 .ssh
    #これが違うと動かなかった。 実行フォルダなんだな
remort$ cd .ssh/
remort$ touch authorized_keys
    #無ければ作っておく
remort$ chmod 600 authorized_keys
remort$ cat ~/id_rsa.pub >> authorized_keys
remort$ rm ~/id_rsa.pub
    #最後にコピーしたキーを削除、後から別のマシーンから設定したりすることもあるので。

これで接続出来る様になっているはず

5) remort$ sudo vim /etc/ssh/sshd_configで設定の変更

これ自分でもどこを変えたかあまり覚えてないんですが、おそらく赤が必須かな?

14行目: #AddressFamily any  → AddressFamily inet     これはIPv4指定

43行目: PermitRootLogin no  → PermitRootLogin yes    これは後でnoに戻しておきますが、とりあえずrootでのログインの設定を完了するまでyesにしておきます。

67行目: 全て設定が終わった後に PasswordAuthentication yes → PasswordAuthentication no  にします。

71行目: ChallengeResponseAuthentication no → ChallengeResponseAuthentication yes  にしてますがなぜしたかよく覚えてないです。 不要かも・・。

82行目: GSSAPIAuthentication yes → GSSAPIAuthentication no  これもよく覚えてないです・・。 不要かも

98行目: UsePAM yes  → UsePAM no  これも不要な気がする。

123行目: UseDNS yes   → UseDNS no これはDNSサーバをローカルに作っていないと接続が遅くなるので noにしといた方が早いです。

126行目: #Match User anoncvs 以降末尾に追記

Match Address 192.168.0.xxx  ☆ 監視サーバーのアドレスをセット
        PermitRootLogin yes
        PasswordAuthentication no
 

 

:wqでセーブして。
remote$ sudo /etc/init.d/sshd reload で設定をリロードできます。

6) sshd_configの設定を変更してからrootでも同様にアクセス出来る様に

shutdown -r nowとか service pcscd restart とかのsuperuser権限のコマンドを使うのに利用します。 sudoerファイルにコマンドを登録しても良いのかもしれません。

rootでアクセス出来る様にしておいたら、sshd_config 43行目はno に戻しておいた方が安全ですね。

7) remort$ sudo vim /etc/hosts.deny  また remort$ sudo vim /etc/hosts.allow 

 結構な頻度で外部からハッキング(パスワード)チャレンジがあるんで、制限かけた方が良いです。

hosts.allowに
sshd:  192.168.1. 自分のローカルIP-range
ssh接続はさすがに制限かけといた方が良いでしょう。

hosts.deny

sshd: all

私の感想

実際このパスワード認証無しでのSSH接続がCentOSに対して上手く出来なくて悩んだ時間が1ヶ月ぐらいありましたわ・・。 このパスワード認証なしでSSH接続が出来るようになる所がこのスクリプト全体の半分ぐらいの労力を使った気がします。 

また理由がわからなくていろいろsshd_configをいじって接続を試していたので、どれが必要な変更かよくわからなくなってしまったのです。 

対話式のApplescriptでのTerminalのコントロール

最後にターミナルで対話型でssh 接続してコマンドを実行するハンドラーをちと紹介です。 まあ凄いガバガバなアップルスクリプトなので、必要に応じて修正してみてください。 

 

set pswd to "******"

set q to {FailSafe:true, ActionList:{"", "@*~ %", "ssh foltia@foltia.local", "assword:", pswd, "@*~]\\$", "sudo ls", "パスワード:", pswd, "@*~]\\$", "exit", "~ %"}, closeWindow:true}

set q to term(q) of me

return q

 

on term(q) --termは基本的に返値なし

     set q to {error_:""} & q & {tab_:"", ActionList:{}, wSec:10, ti:0.1, FailSafe:true, WaitBusy:false, closeWindow:true}

     --FailSafefalseならチェックなし所定時間経過したら進む。

     --Prompt1, Action1, Prompt2, Action2 の順番で処理し、空白が出現した段階で停止する。

     --"$Here"ならproHere, "$There"ならProThereを入れる

     set ProHere to "@*~"

     set ProThere to "@*~"

     if (do shell script "Echo " & (system info)'s system version & "|sed -e 's/\\(^[0-9]*.[0-9]*\\)[^0-9].*/\\1/g'") ≤ 10.13 then set ProHere to "~*\\$"

     

     

     set max to round ( (length of q's ActionList) / 2)

     --偶数個ないと最後は実行されない。

     --tell application "Terminal" to close every window

     

     repeat with i from 1 to max

          if q's tab_ is "" then

               tell application "Terminal" to set q's tab_ to do script item (i * 2 - 1) of q's ActionList

          else

               tell application "Terminal" to do script (item (i * 2 - 1) of q's ActionList) in q's tab_

          end if

          delay q's ti

          set wPrompt to item (i * 2) of q's ActionList

          if wPrompt is "$Here" or wPrompt is "$local" or wPrompt is "$client" then set wPrompt to ProHere

          if wPrompt is "$There" or wPrompt is "$remote" or wPrompt is "$server" then set wPrompt to ProThere

          

          set q to WaitPrompt({tab_:q's tab_, wPrompt:wPrompt} & q) of me & q

          if q's FailSafe then return {error_:"ActionList:" & item (i * 2) of q's ActionList & "が返却されない"} & q

     end repeat

     if q's closeWindow then tell application "Terminal" to close window 1

     return q

end term

 

--パスワードプロンプトはBusy待機中にBusyになる

--return WaitPrompt({wPrompt:"@iMac-17 ~ %"})

on WaitPrompt(q)

     set q to q & {tab_:"", wSec:10, FailSafe:true, wPrompt:"", ti:0.1, SerchFullText:false, WaitBusy:true, LastLine:""}

     

     if q's tab_ is "" then tell application "Terminal" to set q's tab_ to tab 1 of window 1

     if q's wPrompt is "" then

          delay q's ti

          return {FailSafe:false} & q

     end if

     

     

     tell application "Terminal" to tell q's tab_

          if q's WaitBusy then

               repeat while busy is true

                    delay q's ti

               end repeat

          end if

          if q's wPrompt is "" then return q

          set a to ""

          repeat q's wSec times

               set history_ to history as string

               set Len to 1

               try

                    set Len to (length of history_) - 1000

               end try

               if Len < 1 then set Len to 1

               set history_ to text Len thru end of history_

               

               if q's SerchFullText then

                    set a to do shell script "echo " & quoted form of (history as string) & "|grep -v '^$'|tr -d '^\\r'|tr \\\\r \\\\n|grep '" & q's wPrompt & "'||true"

               else

                    try

                         set a to do shell script "echo " & quoted form of (history_) & "|grep -v '^$'|tr -d '^\\r'|tr \\\\r \\\\n|tail -n 2|grep -B 1 '" & q's wPrompt & "'||true"

                    end try

               end if

               if a is not "" then

                    set q's FailSafe to false

                    exit repeat

               end if

               delay 1

          end repeat

     end tell

     return {LastLine:a} & q

end WaitPrompt

 

 

以下参考として

MacUnix環境を入れておきましょう私はMacPorts使ってます

きっとググるといっぱい出てきますが、適当にトップに出た物を上げときます。

blog.fire-sign.info

Homebrewでもよいです。自分の好きな環境を入れておきましょう。 ただ今回のアップルスクリプトではもしかしたら使ってないかもな〜。 もういろいろと入っててデフォルトの状態が思い出せないんですよ。

MacOS上でコマンドファインダー上でCommand+Shift+ピリオド

不可視ファイルを見やすくしておく事ができますが、全部vimやviで操作するので、必要無い方はしなくてよいでしょうね。

番外) 相手がMac-OS ventura以降だとRSAではダメだった 25519を使う

今回出番はありませんが、接続相手が新しいOSだとRSAでの接続を許可していない場合も有ります。 その場合はもう少し新しいキーシステムを試す必要がありそうです。 参考までに。

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
パス設定せず。 あとは上記の

~/.ssh/config

に IdentityFile ~/.ssh/id_ed25519 を指定

さらにコピーするファイル scp ~/.ssh/id_ed25519.pub foltia@foltia.local:  

としますし、

#cat ~/id_ed25519.pub >> authorized_keys remort$ rm ~/id_ed25519.pub とする必要があります。