Mac OSX のインターフェースに複数のアドレスを割り当てる方法

OSXで複数のIPv6アドレスを割り当てたい

自宅のネットワークがIPoEによりIPv6ネイティブ接続になったので、クライアントであるMacにIPv6のアドレスを割り当てようとしました。今回割り当てようとしているIPv6アドレスは、機器に勝手に割り当てられるリンクローカルアドレス(fe80::/64)と、IPoEのRAでふってくるGUA(Global Unicast Address:今回は2409:252::/64)と、いわゆるプライベートアドレス的なULA(Unique Local Address:fd00::/48)の3つです。

リンクローカルアドレスは問答無用で割り当てられるので無視ですが、残りの2つは設定のネットワークを見てもどちらか一方しか割り当てられないように見えます。TCP/IPの設定のIPv6の設定は自動化か、手入力か、リンクローカルのみの三択です。自動はGUAの割当のことです。

さらにULAを割り当てたい場合は、左のペインで「+」を押して、インターフェースを増やします。今回の場合はWi-Fi 2という名前です。

この新しくできたインターフェースのTCP/IPの設定でIPv6の手入力を選択し、ULAを入力します。IPv4の設定や、DNSの設定は全て空白のままでいいです。

/sbin/ifconfigで見ると、IPv6のアドレスが追加されていました。

Netatmoで屋内のCO2を監視する

Netatmoはフランス生まれの気象観測ガジェット。日本でも販売しており、手軽に温度、湿度、気圧、二酸化炭素濃度などが測れます。

二酸化炭素濃度は室内を測っているのだけれど、生活の中ですごく変化する様子が面白い。屋外の濃度はおおよそ400ppmなのだが、室内で窓を閉め切ると人間の呼吸だけであっという間に600〜800ppmほどになります。さらに、調理などでガスコンロを使うとあっという間に1000ppmを超え、冬場の石油ストーブなどは締めきった部屋で使うとみるみる2000,3000ppmと上がっていき見ているだけで息苦しくなる気がします。

通常、1000ppm以下が快適とされている二酸化炭素濃度ですが、Netatmoで計測できても気軽に知る方法がありません。スマホアプリがあるので、スマホのウィジェットやタブレットなどに表示させておけるのですが、それでも見にくい。というわけで、7セグメントLEDとraspberry piを使い常時表示させるガジェットを作りました。

用意するもの

  • Raspberry pi zero WH
  • 自作4桁7セグメント基盤

自作基盤は大変参考になるページが有ったので、そのまま流用させてもらいました。http://cl.hatenablog.com/entry/akizuki7segkit

 

nodejsのインストール

まずはnodejsのインストール。raspbianで提供されているnodejsは古いようなので、新しいバージョンをインストールできるようにnodejsのパッケージマネージャであるnpmをインストールします。

$ sudo aptitude install npm

標準のnodejsを始め、 多数のパッケージがインストールされます。

インストールされるのはnodejsコマンド。バージョンを確認すると以下のようになっています。

$ nodejs -v
v4.8.2

次に、バージョン管理ができる、nコマンドをインストール。

$ sudo npm install -g n

-gでグローバルでインストール。
これで任意のバージョンのnodejsがインストールできるようになります。インストールできるバージョンは n ls で確認できます。特定のバージョンをインストールする際は、バージョン番号を指定して n 9.5.0 のようにします。他にstable , latest , lts などが指定できます。今回はlts(長期サポート版)をインストールします。

$ sudo n lts

     install : node-v8.9.4
       mkdir : /usr/local/n/versions/node/8.9.4
       fetch : https://nodejs.org/dist/v8.9.4/node-v8.9.4-linux-armv6l.tar.gz
######################################################################## 100.0%
   installed : v8.9.4

今回は8.9.4がインストールされました 。今回されたのはnodeコマンドです。

Netatmo API からCO2値を取得

nodejsでnetatmoが使えるモジュールがあるので、インストールします。~/netatmoを用意しておき、そのなかでインストールします。**は適宜読み替えてください。

$ npm install netatmo
netatmo@2.1.0 node_modules/netatmo
├── request@2.83.0 (aws-sign2@0.7.0, tunnel-agent@0.6.0, oauth-sign@0.8.2, forever-agent@0.6.1, caseless@0.12.0, is-typedarray@1.0.0, safe-buffer@5.1.1, stringstream@0.0.5, aws4@1.6.0, isstream@0.1.2, json-stringify-safe@5.0.1, extend@3.0.1, performance-now@2.1.0, qs@6.5.1, uuid@3.2.1, combined-stream@1.0.5, mime-types@2.1.17, tough-cookie@2.3.3, form-data@2.3.1, hawk@6.0.2, http-signature@1.2.0, har-validator@5.0.3)
└── moment@2.20.1

Netatmo APIを利用して屋内ステーションからCO2値を取得するプログラムは以下のnetatmo.jsを用意しました。

var netatmo = require('netatmo');
var fs = require('fs');

var auth = {
  "client_id": "************************",
  "client_secret": "***************************",
  "username": "****",
  "password": "****",
};

var api = new netatmo(auth);

//var getStationsData = function(err, devices) {
//  console.log(devices);
//};

// Get Measure
// See docs: https://dev.netatmo.com/dev/resources/technical/reference/common/getmeasure
var options = {
  device_id: '**:**:**:**:**:**',
  scale: 'max',
  date_begin: '',
  date_end:'last',
  type: [ 'CO2'],
  real_time: true,
};

setInterval(function() {
  api.getMeasure(options, function(err, measure) {
//    console.log(measure.length);
//    console.log(measure[0]);
    var data = (' '+measure[0].value).slice(-4);
    fs.writeFile('/pathto/netatmo/co2.txt', data , function (err) {
//      console.log(err);
    });
  });
}, 60000);

co2.txtというファイルが指定したディレクトリに作られます。テストするには以下のコマンドで実行します。停止はCtrl+Cです。

$ node netatmo.js

CO2値を7セグメントLEDで表示

Raspberry PiにGPIO経由で7セグメントLEDを接続し、CO2の値を表示させる。こちらの方法は全面的に https://gist.github.com/CLCL/ab5be8ddc4caa0d72aa5 こちらのサンプルを利用させてもらった。showco2.jsとして以下を作成。

'use strict';

// akizuki-7seg-10col.js:
// Usage:
// (Raspberry PiにRaspbian Jessieをインストールして、
// sudo raspi-config で SPI使用を有効にしてリブート後、
// piユーザでログイン)
// sudo apt-get update
// sudo apt-get -y remove nodered nodejs nodejs-legacy
// curl -LO http://node-arm.herokuapp.com/node_latest_armhf.deb
// sudo dpkg -i node_latest_armhf.deb
// mkdir 7seg
// cd $_
// npm install onoff pi-spi
// curl -LO https://gist.githubusercontent.com/CLCL/ab5be8ddc4caa0d72aa5/raw/80600eec8e20584d945c7b249ebb001cd2661b59/akizuki-7seg-10col.js
// sudo node akizuki-7seg-10col.js


//
// #Use libs/Global Objects
//

var SPI  = require('pi-spi');
var Gpio = require('onoff').Gpio;
var fs = require('fs');

// SPI初期化
var spi = SPI.initialize('/dev/spidev0.0');
spi.clockSpeed(31250000); // 250MHzの8分周=31.25MHz(実用できる限界速度)

//
// #define
//

// 信号値定義
var HIGH = 1;
var LOW  = 0;
// 信号ピン定義
var LATCH =  25; // GPIO25(22pin):74HC595 LATCH           -> LAT
                 // MOSI(19pin)[変更不可]:SPI DATA OUTPUT -> DAT
                 // SCLK(23pin)[変更不可]:SPI CLOCK       -> CLK

//
// Class
//

var SEG7 = function(f) {
  this.gpio = {
    lat : new Gpio(f.LAT, 'out')
  };
  this.digits = [
    0x3f, 0x06, 0x5b, 0x4f,
    0x66, 0x6d, 0x7d, 0x27,
    0x7f, 0x6f
  ];
  this.gpio.lat.writeSync(LOW);  // ラッチ(LED表示固定)
};

SEG7.prototype = {
  write: function(buf) {
    return new Promise(function(resolve, reject) {
      spi.write( buf, function(e) {
        if (e) console.error(e);
      });
    });
  },
  latch: function() {
    var self = this;
    return new Promise(function(resolve, reject) {
      self.gpio.lat.writeSync(HIGH); // ラッチ解除(シフトレジスタ内容表示)
      self.gpio.lat.writeSync(LOW);  // ラッチ(LED表示固定)
    });
  },
  show: function(f) {
    var self = this;

    var buf = Buffer(f);
    var buf2 = new Buffer(4);
    var j = 0;
    for (var i = 0; i < buf.length; i++) { if (buf[i].toString() == '.'.charCodeAt(0)) { buf2[j-1] |= 128; } else { buf2[j] = self.digits[buf[i]-48]; j++; } } self.write(buf2).then(self.latch()); } }; // // Main Routine // var seg7 = new SEG7({LAT: LATCH}); var timer = Date.now(); (function loop() { var now = Date.now(); if (now - timer > 4096) {
      var text = fs.readFileSync('/home/n10/netatmo/co2.txt', 'utf8');
      seg7.show(text);
    timer = now;
  }
  process.nextTick(loop);
})();

以下のモジュルールをインストール。

$ npm install pi-spi
$ npm install onoff

あと、実行するユーザがpiでない場合は、spi,gpioのグループに追加しておく。

$ sudo gpasswd -a hoge spi
$ sudo gpasswd -a hoge gpio

デフォルトではGPIOが有効になっていないので、sudo raspi-configして有効にする。Interfacing OptionsからSPIをenableにして再起動する。

showco2.jsを起動して、co2.txt内の数字が表示できれば成功。

自動起動(forever)

あとはnetatmo.jsとshowco2.jsを自動起動するだけだが、永続的に起動しておくためにnodejsのforeverを使う。グローバルでインストールしておく。

$ sudo npm install forever -g

起動のために、/etc/rc.localに以下を記述

sudo -u hoge /usr/local/bin/forever start /pathto/netatmo/netatmo.js
sudo -u hoge /usr/local/bin/forever start /pathto/netatmo/showco2.js

時々再起動しないと止まることがあるので、crontabに以下を記述。

0 * * * * /usr/local/bin/forever restartall

これで、深夜0時に再起動がかかる。

twitterに投稿し、voiceloidに喋らせる

 

 

 

Raspberry pi zero w のネットワーク設定

無線の設定

Raspberry pi zero w は無線のインターフェースしかないので、最初のセットアップはモニターとキーボドを繋いでやるのが無難。起動したらまずは無線の設定から始める。

raspi-configで無線のSSIDとPASSWORDは設定できるので、/etc/wpa_supplicant/wpa_supplicant.conを確認しておく。もし、うまく設定できなかったら手動で以下のコマンドでもできる。

sudo wpa_passphrase SSID PASSPHRASE | sudo tee -a /etc/wpa_supplicant/wpa_supplicant.conf

問題はパスフレーズ。’!’などの文字が入っているとコマンドが正常に認識されないので、SSIDやパスフレーズなどは’で囲っておく。

ファイルのパーミッションは念のために600にしておくのが良いだろう。(上のコマンドのままだとPSKの平文が残る。念のためにhistoryも消しておくのが良かろう)

固定アドレス

固定アドレスはかつては/etc/network/interfacesで設定していたが、最近は/etc/dhcpcd.confでやるのが推奨されているらしい。以下を追加しておく

interface wlan0
statuc ip_address=192.168.0.79/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.75

無線はwlan0のインターフェース。

 

SlackのログをEvernoteに定期的にクリップ

Slackのログはライフログ

家庭内Slackを使い始めて2年ぐらいたつんですけど、無償版のSlackは発言が1万しか保存されません。一日30発言で1年ぐらいしか持たないので、結構少ないです。あとから、見返したいときにもうなくなっています。こいつはもったいないので、Evernoteに保存したいと思います。

SlackからEvernoteへの連携

SlackとEvernoteの連携はiftttとか使わなくても公式で連携があります。今回はこれを使います。連携を済ませると新たなスラッシュコマンドが追加されて、コマンドでSlackの発言をEvernoteに保存できます。/clip yesterday とやると昨日の分のチャネルの発言がEvernoteに保存されます。残念ながらノートブックは選べません。ライフログ用のノートブックを既定のノートブックにしました。

Cronで実行

このコマンドを手で入力ではなく、深夜0時を回った時に自動で実行します。Slack API のchat.postMessageでは発言はできますが、コマンドは実行してくれません。「/clip yesterday」という発言をするだけです。かわりに chat.command を使います。

1 0 * * * /usr/bin/curl -X POST "https://{domain}.slack.com/api/chat.command?token={token}&channel={channel_id}&command=/clip&text=yesterday"

channel_idの取得は https://qiita.com/Yinaura/items/bd28c7b9ef614696fb7e ここを参考にさせていただきました。

Mac OSX High Sierra にすると謎のパージ可能領域が消せない件

重い腰を上げてHigh Sierraにアップデート

Mac OSX のメジャーバージョンアップはいつも少し憂鬱。バージョンアップで動かなくなるソフトが出るのは承知のとおりだが、私の使っている大半のソフトはリリースまでに対応済みのことが多い。

問題は仮想化のVMware Fusionである。OSのバージョンアップのたびにVMwareのバージョンも上がり、毎回安くはないアップデート費用を取られる。それほど頻繁にVMwareを使うわけではないので、バージョンアップには乗り気になれない。そんなわけでVMware FusionからVirtualBoxに乗り換えたのだが、それはまた別の話。

ハードディスクのパージ可能領域

High Sierraにアップデートをした直後からハードディスクがみるみる減っていく。不要ファイルを消したり再起動しても一向に空き領域は増えず、むしろ時間とともに減っていく。いくらなんでもおかしいと思い調べたところ、パージ可能領域というのが圧迫しており、これがTime Machineと関係していることが判明した。このパージ可能領域を簡単に削除する方法が簡単ではなかった。

Time MachineはMacのバックアップソリューションだが、ノートパソコンなどではたまに外付けハードディスクをつけてバックアップすることが多いと思う。そんな運用が多いのはお見通しなのか、High Sierraからは外付けハードディスクがない間は内蔵ディスクにローカルスナップショットを保存取得しておく設定がデフォルトになった。これがパージ可能領域の正体だった。

ローカルスナップショットの確認と削除方法

まずはローカルスナップショットの確認

$ tmutil listlocalsnapshots /
com.apple.TimeMachine.2017-11-18-104524
com.apple.TimeMachine.2017-11-18-123140
com.apple.TimeMachine.2017-11-18-183524

ここでは3つのスナップショットが見つかった。削除方法は以下の通り。

$ tmutil deletelocalsnapshots 2017-11-18-104524
Deleted local snapshot '2017-11-18-104524'

これでパージ領域がなくなったはずだ。

ローカルスナップショットの停止方法

残念ながら、停止方法はわからなかった。Time Machineそのものを止めてしまえば、これ以上スナップショットが増えない。もしくは空き領域が極端に少なくなると自動的に削除されるそうだが、こちらは検証していない。

Raspberry piにmirakurunとchinachuをインストール

ハード

  • raspberry pi
  • PX-S1UD V2.0
  • ACR39-NTTCom(USBカードリーダー)

チューナーの設定

http://plex-net.co.jp/plex/px-s1ud/PX-S1UD_driver_Ver.1.0.1.zipをダウンロードして、ファームウェアをコピーする

$ sudo cp PX-S1UD_driver_Ver.1.0.1/x64/amd64/isdbt_rio.inp /lib/firmware

カードリーダー(B-CASカードの)の設定

$ sudo aptitude install pcscd libpcsclite-dev pcsc-tools

B-CASカードを挿入しておき、pcsc_scanコマンドでカードリーダの状態を確認できる。次にB-CASカードをデコードするarib25ライブラリをインストールする。https://github.com/stz2012/libarib25/archive/09770e3.tar.gzをダウンロードして、/usr/local/srcに置き、make ; make installする。

recdvbのインストール

http://www13.plala.or.jp/sat/recdvb/recdvb-1.3.1.tgzをインストール。以下のコマンドを実行。

$ ./autogen.sh
$ ./configure --enable-b25
$ make
$ sudo make install

以下のコマンドで、録画できることを確認する。

$ recdvb --b25 --strip --sid hd 22 10 test.m2ts

10が録画秒数。22の部分が地デジの物理チャンネル。物理チャンネルはこの辺を参照。http://www.maspro.co.jp/contact/bro/bro_ch.html

(2018-02-20追記)
上記コマンドを実行するユーザがvideoのグループに入っていないといけない。そうしないと、cannot open frontend deviceのエラーが出る。以下のコマンドを実行しておく。

sudo useradd hoge video

 

MirakurunとChinachuのインストール

ようやくここまでたどり着く。詳しくは公式を見ながら。(https://github.com/Chinachu/Chinachu/wiki/Gamma-Installation-V2)

curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs

sudo npm install pm2 -g
sudo pm2 startup

ここまでが準備。続いてMirakurun

sudo npm install mirakurun -g --unsafe --production

updateするときは

sudo npm install mirakurun@latest -g --unsafe --production

まずはコンフィグ

sudo mirakurun config tuners

今回のチューナの設定はデフォルトでは入っていないので、以下を追加。

- name: PX-S1UD-1
  types:
    - GR
  command: recdvb --b25 --strip <channel> - -

インストール後にチャンネルスキャン

curl -X PUT "http://localhost:40772/api/config/channels/scan"

この段階で、MirakurunのAPI越しに放送をストリームできる。VLCなどを使い、http://192.168.0.79:40772/api/channels/GR/28/streamを開くと見られるはず。RaspberryPi上のvlcでlocalhostを指定してみようとしたけど、CPU使用率が300%超えてまともに再生できなかった。

あとは録画インターフェースのChinachuをインストール。録画する予定はないが、とりあえず入れてみた。

git clone git://github.com/kanreisa/Chinachu.git ~/chinachu
cd ~/chinachu/
./chinachu installer
# Auto を選択

RasPi2だとコンパイルに死ぬほど時間がかかった。詳しく見ていないが、4時間位?インストール後に設定をする。

cp config.sample.json config.json
vim config.json

とりあえず、uidを1000に設定。

echo [] >rules.json

空のrules.jsonファイルを作成しておき、起動してみる。

./chinachu service wui execute

http://192.168.0.79:20772を開いて、動作していることを確認。Ctrl+¥で終了し、次にEPGを取得する。

./chinachu update

あとはサービスとして立ち上げる。

sudo pm2 start processes.json
sudo pm2 save

この時点で、8GBのmicroSDは1.2GBくらいしか空いていないので、録画なんて問題外。外部ストレージをつければ良いのだろうけど、そこまでするかどうかは未定。

 

 

Raspberry pi インストールメモ

ハード

  • Raspberry pi 2 B+
  • micro SD 8GB
  • 無線LANアダプター(WDC-150SU2MBK)
  • Macbook (SDカード書き込み用)

Raspbianの書き込み

https://www.raspberrypi.org/downloads/raspbian/ からRASPBIAN STRETCH WITH DESKTOPをダウンロード。今回のダウンロードは2017-09-07-raspbian-stretch.zipというファイル。念のためにチェックサムを確認。

$ shasum -a 256 tmp/2017-09-07-raspbian-stretch.zip 
a64d742bc525b548f0435581fac5876b50a4e9ba1d1cd6433358b4ab6c7a770b tmp/2017-09-07-raspbian-stretch.zip

SDカードを挿入し以下のコマンドでデバイス名を取得(今回は /dev/disk2)

$ diskutil list
(略)
/dev/disk2 (internal, physical):
 #: TYPE NAME SIZE IDENTIFIER
 0: FDisk_partition_scheme *8.1 GB disk2
 1: Windows_FAT_32 boot 66.1 MB disk2s1
 2: Linux 8.0 GB disk2s

デバイスを確認したらddで書き込むためにアンマウント

$ diskutil unmount /dev/disk2s1

ddコマンドを使いイメージを書き込む

$ sudo dd bs=1m if=tmp/2017-09-07-raspbian-stretch.img of=/dev/disk2 conv=sync

最近のRaspbianはインストール直後はssh接続ができないようになっている。セットアップ時にsshは使いたいので、出来上がったbootフォルダ内に ‘ssh’ というファイルを作っておく。

$ touch boot/ssh

初期設定

ssh接続

sshで接続するのだが、DHCPで取得しているIPアドレスを調べる必要がある。ディスプレイとキーボドが繋がっていれば、ログインしてifconfigで調べればeth0(有線のイーサネットポート)のアドレスが分かるが、ディスプレイ無しで調べるのは以下の方法で。

$ ping 192.168.0.255
$ arp -a

一行目が、自分のネットワークのブロードキャストアドレス。二行目が、自分のPCのarpテーブルを表示する。arpで調べたアドレスの中に、MACアドレスがb8:27:ebで始まっているものがあるはず。これが、raspberry piのベンダーコードなので、これに割り当てているIPアドレスが今回DHCPで取得したアドレスとなる。今回は192.168.0.244だった。

 $ ssh pi@192.168.0.244

初期ユーザはpiでパスワードはraspberry。とりあえずこれでログインするが、初期設定が終わったらこのユーザは停止する。

raspi-configによる初期設定

$ sudo raspi-config

上記のコマンドによる、初期設定。ここで変更したのは、パスワード、ホストネーム、ローカリゼーション、アドバンスドオプションのSDカードの拡張ぐらい。終了すると自動的に再起動。

アップデート

/etc/apt/source.listに近場のリポジトリを登録

deb http://ftp.jaist.ac.jp/raspbian/ stretch main contrib non-free rpi
$ sudo aptitude update
$ sudo aptitude safe-upgrade

ネットワークの状況にもよるが、数分から数十分だと思う。

$ sudo rpi-update

ファームウェアの更新もしておく

$ sudo reboot

再度リブートしておく

ネットワークの設定

普段は無線LANの運用をするので、以下はその設定。Raspberry Pi 2には無線インターフェイスはないので、USBアダプタを接続。あっさりとwlan0として認識した(/sbin/ifconfigで確認)。固定IPアドレスを設定する。場所は/etc/network/interfacesとなる。今回は以下の行を追加。

auto lo
iface lo inet loopback

allow-hotplug eth0
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet static
    address 192.168.0.79
    netmask 255.255.255.0
    gateway 192.168.0.1
    dns-domain mirahouse.jp
    dns-nameservers 192.168.0.75
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

無線はwlan0のインターフェース。eth0は有線インターフェースで、無線がつながらない時に使うことになるはずなので、dhcpで残しておく。

無線の最終行はセキュリティの設定となる。wpa_supplicant.confにSSIDやPSKの設定を入れておく。具体的には以下のコマンドで設定。

sudo wpa_passphrase SSID PASSPHRASE | sudo tee -a /etc/wpa_supplicant/wpa_supplicant.conf

問題はパスフレーズ。’!’などの文字が入っているとコマンドが正常に認識されないので、SSIDやパスフレーズなどは’で囲っておく。

ファイルのパーミッションは念のために600にしておくのが良いだろう。(上のコマンドのままだとPSKの平文が残る。念のためにhistoryも消しておくのが良かろう)

ユーザの作成とSSH設定

新たにユーザを作成する。group sudoにも追加して、sudoできるようにしておく。ついでにrootのパスワードも変更しておく。

$ sudo useradd -m -k /etc/skel -d /home/hoge -s /bin/bash hoge
$ sudo passwd hoge
$ sudo gpasswd -a hoge sudo
$ sudo passwd root

すでにある、sshの公開鍵をコピーしてsshのパスワード認証を使えないようにする。

(Raspberry pi)
$ sudo mkdir /home/hoge/.ssh
$ sudo chown hoge.hoge /home/hoge/.ssh
$ sudo chmod 700 /home/hoge/.ssh
(クライアント側)
$ scp .ssh/*.pub 192.168.0.79:~/.ssh/
(Raspberry pi ここから新しいユーザでログイン)
$ cd .ssh
$ cat id_edcsa.pub >>authorized_keys
$ cat id_rsa,pub >>authorized_keys

一旦ログアウトして、公開鍵認証でsshできることを確認する。問題ないことを確認したら、/etc/ssh/sshd_configに以下の行を追加。再起動かsshdの再起動を行う。

PasswordAuthentication no

piユーザからsudoのグループを外しておく

sudo gpasswd -d pi sudo

 

 

 

 

ssh-agentとpkcs11をmacOSXで使う

すごくわかりにくいタイトル

YubikeyにSSHの秘密鍵を入れて、ローカルのハードディスクに鍵は置かないといころまではうまく行った。つぎにあちこちのPCやらサーバから鍵を消しまくりたいのだが、接続した先のサーバから別のサーバに接続なんてケースはママある。ということでssh-agentの登場となるわけですが、ssh-agentにファイルとして存在していない鍵(Yubikeyのようなスマートカード)をどう追加するかという話。

ssh-add -s /usr/local/lib/opensc-pkcs11.so

これで行けることはわかっているんですが、Macだとどうしても動いてくれない。どうやらssh-agentのマニュアルを読むと-Pオプションで、信頼できるpkcsライブラリで指定するらしい。これがデフォルトだと/usr/lib*/*と、/usr/local/lib*/*になっているようで、上のopensc-pkcs11.soも問題ないじゃないかと思っていのだが、MacOSXの場合はHomebrewでopenscをインストールしており、上記のパッケージもシンボリックリンクでおいてあった。

-Pオプションにオリジナルの場所を追加しようとしたのだが、どうもうまく行かず、非常に安直なworkaroundだが、オリジナルをコピーして/usr/local/libにおいたらうまく動いた。

アップデートしたら動かなくなるかもしれないし、脆弱性があっても放置される可能性があるので、おすすめはできない。-Pオプションで解決したい。

Yubikey (スマートカード)に入れた秘密鍵を使ってSSHにログインする

ラノベのタイトルみたいになってしまった

すったもんだしてYubikeyにSSHの秘密鍵を入れるところまで行ったのだが、これを利用して、ローカルのハードディスクに秘密鍵を置かずに、SSHのログインを使用という話。クライアントはWindows,Mac,Linuxを想定している。
いままで、公開鍵暗号でのSSH接続ができていたことが前提。

Mac,Linux

Yubicoのページ( https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html )のStep 4 からほぼそのままでいけた。

まずはOpenSCのインストール。Mac OSX の場合はhomebrewでインストールするのがよさ気。

brew install opensc

これだけでいける。インストール先は/usr/local/opt/openscになる。環境によっては、/usr/local/Cellar/openscになることもある。インストールされたディレクトリは以下のコマンドでも確認できる。

brew --prefix opensc

OSXはメジャーバージョンアップの際に/usr/localにものがあるとしくじる前科があるので若干心配だ。Linuxの場合は、それぞれのパッケージ管理ソフトに従う。

次に参考したページにはssh-keygenで公開鍵を取り出して、リモートホストのauthorized_keysに追加せよとあるが、今まで同じ鍵でサーバ運用していた場合は関係なし。

必要なのはpkcs11のライブラリの場所を調べてそいつがスマートカードを読み取れるかどうか。ちなみに手近のLinuxクライアントはVMware Player のDebianしかないのだが、VMのゲストOSがスマートカードを認識できないので確認できない。(no slotsというエラーが出る)

あとはsshコマンドを叩くときにIオプションでpkcs11ライブラリの場所を指定するだけ。

ssh -I /usr/local/opt/opensc/lib/opensc-pkcs11.so remotehost

こうするとYubikeyの中の秘密鍵を使ってセッションを確立します。しかしこれを毎回打つのは面倒なので、~/.ssh/configに記述しておきます。私の場合はこんな感じ。

Host hoge
        Hostname          hoge.example.jp
        Port              12345
        PKCS11Provider    /usr/local/opt/opensc/lib/opensc-pkcs11.so

 

4行目に書いてあるPKCS11Providerが追加されたところ。

Windows

WindowsのSSHクライアントといえば、TeratermかPuttyが思い浮かぶ。そんな人に手っ取り早いのが、Puttyの中に入っているPageantを使う方法。認証エージェントですが、スマートカード対応版があります。Puttyシリーズをスマートカード対応にしているPutty-CACというプロジェクトがあってバイナリを公開しています。

SSHサーバに接続するだけなら、Putty本体とTeratermでも使えるPageantをダウンロードするだけで大丈夫です。

Puttyそのものの使い方は割愛しますが、接続先ホストの設定でConnection-SSH-Certificationとすすみ、Attempt Certification Authentication にチェックを入れて、Set CAPI certで証明書を選び、PIN入力が出てくれば接続可能です。

同じようにpageantにも証明書を指定しておき、Teratermで接続する際にSSH認証で、pageantを使う、でPIN入力が出てくれば接続可能です。

pageantはOS起動時に起動させれば良いと思います。

その他

それにしてもECDSAの鍵を使えないのが痛い。。。

Yubikey 4 にSSHの秘密鍵を格納する

 

Yubico社のYubikey4は単なるワンタイムパスワード生成器じゃなくて証明書を格納可能になった。SSHの秘密鍵をYubkikeyに入れて、sshでログインするときだけYubikeyをPCに挿せば、秘密鍵をあちこちのPCに保存しておく必要がなくなり安心である。Yubikey4は日本のAmazonでも販売されている(AA)

Yubikey自体に鍵生成機能があるので、そこで秘密鍵と公会議のペアを作っても良いのだが、あちこちのサーバの公開鍵を置き換えるのが面倒なのと、Yubikey内で生成した秘密鍵はセキュリティ上取り出すことができないので、既存の鍵を使いたい。当然鍵は取り出せないのが安全なのだが、万が一Yubikeyごと秘密鍵をなくしてしまったら二度とその鍵でログインできなくなるのが怖いのだ。ちなみに、既存の秘密鍵をYubkikeyに入れたものも取り出せないので、一通り設定が終わったら、あちこちのPCにある秘密鍵を消し去って、信頼できるところにだけ秘密鍵のコピーを持っておくつもり。なんなら秘密鍵を紙に印刷しておくのが一番安全かもしれない。

以上の理由で、既存の秘密鍵をYubikeyに入れるのだが、やり方が簡単ではなかったのでメモっておく。前提として、rsa 2048bitの秘密鍵 id_rsa を格納するとする。

 

鍵の変換

まずは既存の鍵の変換から。sshの鍵生成は普通ssh-keygenで行うと思うのだが、これで作られる秘密鍵と公開鍵はopensshの独自仕様のようなので、まずはPEM形式に変換する。PEMとかDERとかいうのは鍵のエンコーディング形式でPEMは鍵をBASE64でエンコーディングしてあり、DERはバイナリのようだ。opensshはBASE64なのだが、PEMとヘッダーとかが違うそうだ。

opensll rsa -in id_rsa -out ide_rsa.pem -outform pem

これでPEM形式に変換。

次に同じように公開鍵も作る

openssl rsa -in id_rsa.pem -pubout >id_rsa_pub.pem

 

Yubikey4のPINコード等の変更

次にyubico社からダウンロードしたyubico-piv-toolを使う。ただしサンプルのとおりにコマンドを打ってもエラーが出る(Windows)ので多少工夫が必要。まずは、yukbikeyをUSBに差し込んで、まずはPINコード、PUKコード(管理者用)、マネジメントキーを変更する。

まずマネジメントキーを登録する。

yubico-piv-tool -a set-mgm-key -n (16進数48文字)

すでにマネジメントキーが登録されている場合は、-kオプションのあとに既存のキーを書く。不思議なのは、-kオプションの後にスペースをおいてキーを指定してもうまく動かない。オプションの後のスペースはあってもなくてもいいのだが、kオプションだけはなぜかスペースがあるとうまく動かない。

yubico-piv-tool -a set-mgm-key -n (16進数48文字) -k(古いマネジメントキー)

次にPIN

yubico-piv-tool -a change-pin

デフォルトのPINは123456で、同じくデフォルトのPUKは12345678。

yubico-piv-tool -a change-puk

同じく変更する。

この辺のキーの変更はGUIツールのほうが使いやすい。(ただしGUIツールはなぜかPUKコードが変更できない。なんだか中途半端……)

あと、好みではあるが、リトライ回数を設定する。

yubico-piv-tool -a verify -P(PIN) -a pin-retries --pin-retries=15 --puk-retries=15 -k(mgm key)

秘密鍵の格納

PEM形式に変換した秘密鍵をyubikeyに格納する。yubico-piv-toolのマニュアル( https://www.yubico.com/wp-content/uploads/2016/05/Yubico_PIV_Tool_Command_Line_Guide_en.pdf )によるとyubikeyの証明書を保存する領域は9a,9c,9d,9eと4つあるようで、9aがPIV Authentication、9cがDigital Signature、9dがKey Management、9eが- Card Authenticationらしい。今回は9aに格納する。

yubico-piv-tool -a import-key -s 9a -i id_rsa.pem -K PEM -k(マネジメントキー)

公開鍵の自己署名証明書作成と格納

次に公開鍵を自己署名する。自分で作った秘密鍵の正当性をどのように担保するかについて、第三者にお墨付きをつけてもらう方法もあるが、今回の目的は他人に自分の秘密鍵の正当性を主張したいわけではないので、自分の秘密鍵の正当性は自分で担保する。これをwebでやるといわゆるオレオレ証明書になるやつだ。今回、yubkikeyはOSから見るとスマートカードとして見えるので、SSHの秘密鍵の対になる公開鍵を自己署名して、自己署名証明書を作り鍵ペアをyubikey内部においておく。まずは公開鍵の自己署名証明書から。

この操作は指定されたスロットに秘密鍵が入っていることが前提。秘密鍵を入れずにやってもエラーになる。

yubico-piv-tool -a verify-pin -a selfsign-certificate -s 9a -S "/CN=SSH/" -i id_rsa_pub.pem -o 9a-cert.pem --valid-days=(日数)

この操作にはPINコードが必要になる。Sオプションはx.509証明書の記述だ。最低限CN(Common Name)さえ入っておけば大丈夫だと思う。OSの証明書選択画面などで使われる名前だ。–valid-daysは証明書の有効期限で、指定しないとでおフォルトで365日となる。試しに1日で作ったのだが、2日経っても期限切れの証明書が使えた。本当に意味あるのか不安。

次に、この証明書をyubikeyに格納する。

yubico-piv-tool -a import-certificate -s 9a -i 9a-cert.pem -K PEM -k(マネジメントキー)

以上でyubikeyに対する操作は終了

yubico-piv-tool -a status

で証明書の状態を確認できる。

CHUIDの作成

普通は必要ないと思うが、実験などでハードウェアリセットをかけてしまうとCHUIDがなくなってしまう。ランダムでCHUIDを発行する必要がある。

yubico-piv-tool -a set-chuid -s 9a

その他

同じ手順で、ECDSA384bit鍵の登録を試みた。同じ鍵を複数鍵を登録することは不可能なので、スロット82に格納してみたいが、Windowsからだと証明書の一覧にECDSAの鍵が出てこない。スロット82だとダメなのかと思って、9aに入れてみたが、やっぱり出てこない。