まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

2020/12

趣味で古い PC の環境を残しているのですが、しばらくの間、動作確認ができなかった環境を動作させることに成功した時の話です。同じ悩みを持つ人はほとんどいないと思っていますが、備忘録としてブログエントリに残しておきます。


【KVM 環境下の Windows7 内で Virtual PC を動かす必要に迫られた背景】
もともとはずっと OS/2(Warp 4) が動作する環境を残しておきたいと思っていました。最大の理由は「ノーツのバージョン1」が動く、数少ない環境だから」です。それ以外だと同様にして DOS 版 Lotus 1-2-3 や懐かしい DOS ゲームが動くという意味での PC-DOS が動作する環境も残しておきたいと思っていました。ちなみにこれらのインストールメディアは OS 含めて今も持っています。

この環境を残す、という目的のためだけに、しばらくの間は実際にこれらが導入された PC (OS/2 は IBM Aptiva、PC-DOS は東芝 Libretto)を残していました。西暦 2000 年頃の話です。

ただ「個人管理でハードウェアを残す」のはやはり大変でした。なにしろ「滅多に電源すら入れない PC を決して広くもない家に捨てずに残しておく」わけです。ソフトウェアやハードウェアの知識も陳腐化してゆきます。

転換期となったのは「仮想化ソフトウェア」でした。VMWare Workstation をはじめとする PC の仮想化により、ハードウェアそのものは不要となり、ハードディスクをイメージ化することで、ソフトウェアだけでこれらの環境を残すことが可能になりました。PC-DOS は今でも多くの仮想化ソフトウェアで動作しますが、OS/2 が動く仮想化ソフトウェアはあまり多くありませんでした。しかし Microsoft Virtual PC だけは当初のバージョンから OS/2 も動かすことができ、OS/2 を仮想環境下で動かすことが可能となりました。これを知った直後から自分は当時使っていた Microsoft Windows 環境内で Virtual PC を使って OS/2 と PC-DOS 環境を仮想化して残すことができました。

時は流れ、Windows 7 のサポート終了(2020/01/14)が近づくと、多くの Windows 7 ユーザーが Windows 10 へと環境移行しました。自分もメイン機は早々と Windows 10 へ乗り換えました。が、この Windows 10 では Virtual PC は動作しない(サポートされないではなく動作しない、インストールもできない)という問題がありました。ずっと残してきた OS/2 や PC-DOS 環境は Virtual PC 環境向けのイメージとなっていて、動かしていた当時のハードウェアはとっくに残してありません。Virtual PC を動かすためには Windows 7 が必要となり、Windows 7 を動かすためだけに専用の PC を残しておく必要があり、・・・となってしまうと元々上述した問題と同じことになってしまいます。

そこで考えたのが「仮想環境化で Windows7 環境を作り、その中に Virtual PC をインストールすれば今の OS/2 や PC-DOS の仮想資産を残すことができる」でした。当時の自分は Linux をベースとした仮想化システムに興味があり、当時の CentOS 6 の標準機能でもあった KVM を使った仮想環境構築にはある程度慣れていました。このような紆余曲折を経て KVM 環境化に Windows7 をインストールして、その Windows7 内で Virtual PC を使うという環境が生まれることになりました。


【KVM 環境下の Windows7 内で Virtual PC を動かしてわかった問題点】
KVM はある程度わかっているつもりでしたので、KVM 環境で Windows7 の仮想マシンをインストールして動かすこと自体は問題ありませんでした。またその環境にVirtual PC(2007) をダウンロード&インストールすることも普通にできました。あとは Virtual PC を実行して新しい仮想マシンを既存の(PC-DOS と OS/2 それぞれの)イメージファイルを使って作るだけ、と思っていました。

が、ここで大きな問題が発生しました。KVM 環境の Windows7 にインストールした Virtual PC を実行しようとすると、実環境下ではみたことがない以下のようなエラーが発生してしまいました。Virutal PC の実行直後(既存の仮想マシン一覧が表示される前)にこのエラーが発生してしまうため、実行を諦める以外の選択肢がありません:
2020122601


このエラーメッセージ(「このコンピュータの物理プロセッサとは互換性がありません」)の意味がわかりにくく、最初は 64 ビット版の Virtual PC と間違えて 32 ビット版の Virtual PC をインストールしてしまったのかと思いましたが、この推測は間違っていました(64 ビット版 Windows7 に 32 ビット版 Virtual PC をインストールしようとすると、インストール中にエラーとなり、インストールは完了しません。今回はインストールまでは完了しているのでこの現象とは異なります)。

ともあれ、Virtual PC が動かないのであれば、既存の Virtual PC で動作実績のある仮想ディスクファイルが存在していても PC-DOS や OS/2 を動かすことはできません。結局の所 Windows 10 環境へ移行したタイミングで OS/2 が動作する仮想環境を失ってしまうことになりました(PC-DOS は動かそうと思えば KVM 内で直接動かすことは可能でしたが、OS/2 は KVM では動きません)。特殊な環境ということもあったのか、この現象をググって調べても解決することはありませんでした。そのため OS/2 の動作環境を残すという目的のためだけに Windows7 の実機を残しておく必要に迫られ、結局「IBM Aptiva を残しておいた頃と同じ、元に戻ってしまう」ことになってしまったのでした。

ここまでが約1年前の話です。その後、この問題が未解決のままだったことをすっかり忘れてしまい、そのまま約1年が経過して、年末の PC 環境整理中に再びこの問題を思い出すことになったのでした。


【KVM 環境下の Windows7 内で Virtual PC を動かすために必要な設定】
改めてエラーメッセージ(「このコンピュータの物理プロセッサとは互換性がありません」)を、KVM というキーワードと合わせてググってみても同様の現象を見つけることが出来なかったので、もう解決策があるという前提で試行錯誤で行くしかありません。

で、仮想マシンの KVM 側の設定を眺めているうちに、このような画面にたどり着きました:
2020122600


KVM 側から見た、仮想マシンの Processer 設定画面です(普段はこのような画面を見る必要すらないので、こんな設定項目があることすら気づいていませんでした)。物理 CPU の割当数を変更したりする画面なのですが、その中に Configuration という項目があり、モデル欄が空になっています。。

このモデル欄は "486" とか "Pentium" といった CPU モデルを選択可能な項目になっているのですが、そのモデルが選択されていないため空になっている、という設定内容でした。念の為書いておきますが、他の Windows や Linux 仮想マシンでも、このモデル欄は空の設定になっていて、それでも問題なく動いています。実際この Windows 7 でも Virtual PC を導入しようとするまでは、この設定で問題にはなっていませんでした。

試しにここで "Copy host CPU configuration" ボタンを押して、ホストマシンの CPU 情報を参照して同じ設定にしてみました(モデル欄には "Opteon_G3" という値が自動入力されました。この値でなくても、ホストで使われている CPU の値が指定されていれば大丈夫だと思います)。この状態で「適用」しました:
2020122602


そして改めて仮想マシン(Windows 7)を起動し、Virtual PC を実行すると・・・ なんと!問題なく実行され、初期画面(新しいバーチャルマシンウィザードの開始画面)が表示されました:
2020122603


そのまま作業を進めて、別の Windows7 機で動いていた PC-DOS の仮想ディスクをコピー&指定して作成した PC-DOS 仮想マシンを動かすことができるようになりました!
2020122604


OS/2 環境も同様に KVM 環境下の Windows7 内 Virtual PC で動作させることができるようになりました:
2020122605


2020122607


いやあ、ここまで長かった! とりあえず KVM 内の Windows 7 では Virtual PC を動かすこと自体ができないのではないかと半ば諦めていたのですが、なんとか解決することができました。 めでたし、めでたし。。


ちなみに、元々のエラーメッセージでは「少なくとも Pentium II」が必要と書かれていました:
2020122601


じゃあ、このプロセッサー情報を(ホストと同じではなく)"Pentium II" と指定して適用すればいいのではないか? と最初は考えていました。が、そのように設定すると Pentium II と同様のウェイトがかかってしまうようでした。その結果、Windows 7 の起動そのものにものすごく長い時間がかかるようになりました(下画面は通常環境だと一瞬だけ表示されるもので、ユーザーが目の当たりにすることはほぼないのですが、プログレスバーがゆっくり進む様子が見て取れました)。そしてその結果なのか、何度も起動と途中終了&強制リセットを繰り返す無限ループに入ってしまい、起動することはありませんでした:
2020122608

↑Windows 7 時代では貴重な起動画面のスクリーンショット

アキネーターの API が存在することを知ったので、使ってみました。ついでにこれを使ったウェブアプリを作ってソースコードごと公開してみました。


【アキネーターとは】
「思い浮かべた人を当てる」ウェブサービスです。基本的にはアキネーターからの質問に「はい」「部分的にそう」「わからない」「たぶん違う」「いいえ」の5つから選んで回答していくことで対象を絞り込み、かなりの高確率でその思い浮かべた人を当ててきます。

日本語のウェブ版はこちらから遊ぶことができます。スマホのアプリも提供されています。もし知らない人がいたら、以下を試す前に是非一度使って、その凄さを体験してみてください:
https://jp.akinator.com/

2020122505


【アキネーター API とは】
このアキネーターの機能を外部から利用するための API です。Node.js 向け npm パッケージ(aki-api)として提供されています:
https://github.com/jgoralcz/aki-api

2020122504


提供されているのは参照用の API のみのように見えます。つまり新しいキャラクターを登録したり、思い浮かべた人が間違っていた時のフィードバックの機能などは API に含まれていないようです。最初の質問を返して、それに答えて、答えると次の質問を返して、また答えて、・・・を繰り返します。答えるたびにその時点での確信度も更新されます。そしてどこかのタイミングで「決定」すると、その時点での回答候補と判定確率の一覧を参照することができる(普通はその中で最も確率の高い人を答えることになります)、といった機能を持っています。

アキネーター API は Node.js で動かすこと自体は簡単ですが、ウェブアプリケーションの中で使おうとすると、少し工夫が必要です。そのあたりの解説を含めて API の説明を後述していきます。


【アキネーター API の使い方】

以下ではアキネーター API の具体的な使い方を説明します。


準備

まずアキネーター API を利用するための動作環境として Node.js 8.2.1 以上、npm 5.3.0 以上が必要です。これらのバージョン以上の Node.js および npm をインストールしておく必要があります。

アキネーター API を利用する前に以下のコマンドで aki-api パッケージをインストールしておきます:
$ npm install aki-api --save

インスタンス化するまで

ここからは実際のプログラムの内容を紹介します。

アキネーター API を利用するには、まず以下のコードでライブラリを呼び出します:
var { Aki } = require( 'aki-api' );

そして以下のようなコードで変数 aki にインスタンス化します。インスタンス化時に対応言語をパラメータで指定する必要があります(下の例では "jp"(日本)を指定しています):
var aki = new Aki( 'jp' );

なお、この時に指定可能な対応言語の一覧は以下のコードで取得できます(regions 変数内に文字列配列で格納されます):
var { regions } = require( 'aki-api' );

こうしてインスタンス化した変数 aki を使ってアキネーターが操作できるようになります。


ゲームを開始して、質問と回答を繰り返して、推測した人を特定するまで

ここからが実際のアキネーターの挙動に関わる部分の説明となります。API の肝の部分です。なおアキネーター API の多くは非同期に実行されるため、同期処理する場合は await を付けて実行する必要があります。以下の説明で await を付けて実行している部分がその該当部分だと認識ください。

まずインスタンス化したアキネーターの推測を開始するために start メソッドを実行します:
await aki.start();

スタートしたインスタンスからは(後述の win メソッドを実行するまで)いくつかのプロパティを参照できるようになります。アプリケーション化する上で必要と思われる代表的なものを以下に紹介します:
プロパティ内容
currentStepここまでの推測に要したステップ数(初期値は 0)
questionこの時点でのアキネーターからの質問内容。インスタンス化時に指定した言語での質問となる(例:「男性ですか?」)
answers質問への回答選択肢の配列。インスタンス化時に指定した言語での質問となる(例:「はい」「いいえ」「わからない」・・)
progressこの時点でのアキネーターの回答確信度(0~100)


アキネーターからの質問内容は aki.question に格納されています。その質問に対する回答選択肢は aki.answers に文字列の配列で格納されていますが、回答選択肢の内容は途中で変化することはありません(例えば 'jp' でインスタンス化した場合は、「はい」「いいえ」「わからない」「部分的にそう」「多分ちがう」の5つで常に固定されます)。

ユーザーはこの選択肢から1つ選んでアキネーターに回答するわけですが、その回答を行うメソッドが step です。パラメータとして上述の回答選択肢のインデックス番号を指定します。例えば「はい」と答える場合は「はい」は配列の最初(0番目)の選択肢なので、パラメータに 0 を指定して実行します:
await aki.step( 0 );  //. 「はい」

「いいえ」の場合は同様にパラメータに 1 を指定して実行します:
await aki.step( 1 );  //. 「いいえ」

step メソッド実行後、aki インスタンスの currentStep, question, progress の各プロパティ値が更新されます(answers プロパティは固定)。回答後にステップ数がインクリメントされ、新しい確信度と新しい質問が取得できるようになります。

start メソッド実行後の、アキネーターとしての基本的な挙動は、この
  • aki.question の質問をして、
  • aki.answers から選んだ選択肢(のインデックス番号)を aki.step() に与えて回答する
を繰り返していくことになります。

これを繰り返している中で、アキネーターは勝手に推測をやめることはありません。どこかで「もう充分」と判断して推測をやめる、という決断をする必要があり、その判断基準やロジックは API 利用者に委ねられています。つまり決断タイミングや基準をプログラマーが決める必要があります。例えば「アキネーターの確信度が 70% を超えたら推測を終了する」のようなルールを決める必要があります(実際に動かしてみた上での感想ですが、実際のアキネーターはもう少し慎重に 70% よりは上の確信度を推測終了のしきい値にしているように思えます)。

アキネーターの推測を終了する場合は win メソッドを実行します:
await aki.win();

win メソッドを実行すると step メソッドは実行できなくなります。また win メソッド実行直後に answers プロパティが変化し、回答の選択肢ではなく、この時点までに推測していた人の上位数名を示す配列値に変わります:

(win メソッド実行後のインスタンスのプロパティ)
プロパティ内容
answers 推測結果の配列
[
  {
    id: "nnnn",
    name: "1番確率が高いと推測した人の名前",
    description: "推測した人の職業など",
    absolute_picture_path: "推測した人の画像URL",
    proba: "この人が答の確率",
      :
  },
  {
    id: "nnnn",
    name: "2番目に確率が高いと推測した人の名前",
    description: "推測した人の職業など",
    absolute_picture_path: "推測した人の画像URL",
    proba: "この人が答の確率",
      :
  },
    :
]


win メソッド実行後の answers プロパティには答えの候補と考えられた数名の名前が含まれているので、(一般的には)配列の最初の要素の人の名前や画像を表示して「この人ですか?」と確認することになります。

ここまででアキネーターとしての挙動は完了します。もし同じインスタンス変数(aki)を使って、このまま別の人の推測を繰り返す場合は、再度インスタンスの初期化をしてから同じ流れを繰り返すことになります:
aki = new Aki( 'jp' );  //. 再初期化
await aki.start();  //. 再スタート

  :

【アキネーター API をウェブで使う場合の工夫】

アキネーター API そのものの使い方は上述のようになります。いくつかのメソッドとプロパティを使うだけでアキネーターが実装できるようになっていて、とても便利です。

ただ、この API をウェブで(不特定多数の複数人で)使おうとすると少し工夫が必要です。理由はこのインスタンス自体がセッションのような情報を持っていて、ユーザー間で共有するわけにはいかない※、という事情があるからです。

※具体的にはこんな感じです。Aさんが初期化して、ある程度進めた所で B さんが初期化してしまうと A さんのセッションがおかしくなってしまいます。また B さんもある程度進めた所でまた C さんが初期化してしまったり、セッションがおかしくなったことに気づかない A さんが B さんのセッションも更に進めてしまったりして、整合性が保てなくなってしまうことが考えられます。

したがってアキネーター API をウェブで使う場合はユーザー毎にアキネーター API インスタンスを用意する必要があります。ということはユーザーを識別する必要もでてきます。ログインを必須にするなどすればここは可能ですが、より気楽にユーザー登録なしに実行できるようにするにはクッキーを併用するなど、ちと面倒そうな工夫も裏で必要になってしまいます(そこまでの機能は API 側には実装されていなさそうです)。


【サンプル】
・・・と、この工夫に踏み込んだところまで含めてソースコードを解説すると本来のアキネーター API の説明の範囲ではなくなってしまう上にちと面倒な内容も含むので、実際に動くサンプルを参照し、必要に応じてそのソースコードを観ていただく形とさせていただきます。

実際に動くサンプルアプリはこちらです(ランプ魔神の画像はいらすとや様から拝借しました):
https://myakinator.mybluemix.net/

2020122501

2020122502
(本当は5位の本仮屋ユイカさんのつもりだった・・・)


わざと確信度が 70% を超えたタイミングで(本物のアキネーターと比べて、確信度が深まる前の段階で)win メソッドを実行して回答候補を表示するようにしています。なので本物のアキネーターと比べてズバリ当たる確率は低いのですが、同時に回答候補となった人の一覧も表示するようにしていて、その中には正解が含まれることが多いような印象を持っています(本物はもう少し確信度が高くなってから回答候補を出しているのだと推測しています)。

で、このサンプルアプリのソースコードがこちらです:
https://github.com/dotnsf/myakinator

2020122503


ユーザーごとにランダムな ID を生成し、その ID をクッキーで管理しつつ、アキネーター API のインスタンスもユーザー毎に生成して管理することで上述の問題点を回避しています。まあ興味ある方はソースコードを覗いてみてください。



毎年恒例のマンホールマップ年間アクセスランキングを発表します。2020 年にマンホールマップでもっとも人気のあったマンホール蓋をベスト10形式で紹介します。また今年新たに投稿された蓋の中で最も人気があった「新人賞」と、今年最も多くの蓋画像を投稿いただいた方「最多投稿賞」を紹介します。

集計のルールとしては 2019/12/21 (今回からルールを変えました。2020/01/01 からではなく、前回の集計期間直後から集計します)から 2020/12/20 までの集計期間における、PC およびスマホのブラウザから単独ページとしてのアクセス数を集計しています。ページビューとしての集計なので、例えば同じページの画面をリロードした場合は1回とだけカウントされます。

なお、過去6回の結果はこちらを参照ください:

2020 最多投稿賞

まず今年は集計期間中に 1050 枚ものマンホール画像が投稿されました。この集計を取り始めた 2014 年以降では最多(※)となりました。 コロナ禍に見舞われた1年でしたが、今年も多くの皆様からの投稿によってマンホールマップは成長し続けることができました。改めて投稿に協力いただいた皆様、ありがとうございました。

※今年から集計期間を当年の1月1日以降ではなく、前年の12月21日以降(12月20日までは前年の記録として判断しているため)としてまる1年間の集計をするように変更しました。そのため集計期間が伸びていることの影響はあるかもしれません。ちなみに前年までと同じ集計方法では 1006 枚の投稿が記録されており、こちらは最多タイでした。

そして今年マンホールマップに最も多くの画像を投稿いただいたユーザーに与えられる賞、それが最多投稿賞です。今年もマンホールマップに有効に投稿された全画像の大半が昨年も激しく一位を争った minamu4545 様と 42ER03 様の2名のユーザーによって提供されたものでした。今年も感謝の限りでございます。 m(__)m

今年も昨年を上回るレベルでの激しい1位争いの結果、 minamu4545 様が今年1年間で 448 枚もの蓋画像を投稿いただき、2年ぶりの1位返り咲きとなりました!おめでとうございます!!

そして今年もハイレベルな一騎打ちを演出いただき、惜しくも僅差で2位となった 42ER03 様、ありがとうございました。

なお、3位はマンホールナイトでもお世話になっている期待の新星 iamokura_2 様でした。

ちなみに私自身は今年は6位でした。昨年の5位から1ランクダウンとなりました。まあおとなしく自粛していた証拠ということで・・・ (^^;



2020 新人賞&総合ランキングベスト10

いよいよ 2020 年マンホールマップ年間アクセス数ランキングを発表する時がやってまいりました。総合ランキング1位となる MVM(Most Variable Manhole) の座はどの蓋に!?


まずは 10 ~ 4 位です。

今年も10位が大激戦でした。2票差の中に8つの候補がひしめく大激戦の結果、2つの蓋が同点で10位となりました。まずは1つ目の第10位!

順位昨年順位市区町村投稿者画像
10 - 東京都稲城市 kayo_kerorine


東京都稲城市、稲城大橋に設置されたカラー蓋でした。多くの投稿をいただいている kayo_kerorine さんから 2014 年に投稿いただいた蓋写真でした。kayo_kerorine さんからはマンホールマップに多くの投稿をいただいていますが、自分の記憶が正しければ年間ベスト10入りは初めてだと思っています。

同点の第10位!

順位昨年順位市区町村投稿者画像
10 - 宮城県石巻市 minamu4545


宮城県石巻市、「せせらぎの小径」が描かれた美しい蓋でした。最多投稿も記録された minamu4545 さんからの投稿作品でした。

実は8位も同点で2作品あります。最初の第8位!

順位昨年順位市区町村投稿者画像
8 - 広島県広島市 morimo_t


広島県広島市、マンホール愛好家の枠を超えて有名な「カープ坊やマンホール」が今年も多くのアクセスを記録して第8位となりました。投稿者は「マンホーラー」生みの親でもある morimo_t さんでした。

同点の第8位!

順位昨年順位市区町村投稿者画像
8 - 兵庫県明石市 42ER03

兵庫県明石市、水道局の排泥弁にデザインされた明石海峡大橋の蓋が同率の8位でした。最多投票では惜しくも2位でしたが、コンスタントに画像を投稿いただいている 42ER03 様からの画像でした。

なお、この蓋画像はこの1年間に投稿された全 1050 枚の画像の中で最もアクセス数の多い画像でもありました。というわけで 2020 年マンホールマップ新人画像賞の栄光はこの蓋ということになりました。43ER03 様、改めておめでとうございます。



第7位

順位昨年順位市区町村投稿者画像
7 - 東京都稲城市 EkikaraManhole

東京都稲城市、第10位で紹介した蓋の色違いバージョンでした。投稿者はマンホール会では超有名な EkikaraManhole 大先生でした。

第6位!

順位昨年順位市区町村投稿者画像
6 - 東京都稲城市 morimo_t

東京都稲城市のかわいい消火栓蓋、この投稿者も morimo_t さんでした。稲城市の特産である梨も描かれてますね。

第5位!

順位昨年順位市区町村投稿者画像
5 - 長野県駒ヶ根市 SatoMachiya

長野県駒ヶ根市のいわゆる「テトラポッド柄」マンホールです。「中」という字はこの地区である「中割地区」を意味しているものと思われます。マンホールマップ初期から利用いただいている SatoMachiya さんからの投稿作品でした。

第4位!

順位昨年順位市区町村投稿者画像
4 - 東京都稲城市 minamu4545

これも東京都稲城市のものでした。昨年から東京都内に多くのデザインマンホールが設置され続けててい、稲城市にも多くのデザインマンホールが設置されました。これはその中の1つで、昨年設置された「マグナムエース」蓋です。最多投稿に輝いた minamu4545 さんからの提供画像でした。


ではランキングトップ3の発表です。が、今年は2位も同率で2つありましたので、この2つを発表します。

まずは1つ目の第2位

順位昨年順位市区町村投稿者画像
2 7 東京都中央区 dotnsf


昨年7位から順位を上げた東京都中央区、お江戸日本橋に設置されている「日本国道路元標」のレプリカ蓋が2位となりました。これは私 dotnsf が投稿した画像でもあります。

もう1つの第2位

順位昨年順位市区町村投稿者画像
2 - 東京都渋谷区 dotnsf

これもマンホールマップを代表する画像の1つで、東京都渋谷区の渋谷ハチ公周辺に設置された「ハチ公蓋」です。待ち合わせのメッカともいえる場所に設置されていて(人に踏まれていない状態での)撮影が非常に難しい蓋とされているのですが、外出自粛となった今年はどうだったんでしょうかね?なお、この蓋も私が投稿したものでした。つまり2つの2位はどちらも僕のでした、不正疑惑? (^^;


そんな特別な 2020 年の栄えある MVM は果たしてどの蓋に!? 今年のグランプリの行方はっ!?

第1位!!

  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓
  ↓


順位昨年順位市区町村投稿者画像
1 - 長野県千曲市 SatoMachiya

長野県旧埴科(はにしな)郡戸倉町(現千曲市)の町花である「ツツジ」、「マヨイグサ」、「キク」がデザインされた美しい蓋です。初期からずっとマンホールマップをご利用いただき、今年の第5位も獲った SatoMachiya さんが、ついに 2020 年の MVM 獲得です。おめでとうございます!!



【考察】
2020 年の MVM となった蓋はコンスタントにはそれほどアクセスがある蓋ではないのですが、たまにスパイクといえるアクセスを記録することに加えて、7月と9月に謎のアクセス(笑)が多くあり、そのアドバンテージを守り抜いての MVM 獲得という結果になりました。
2020122100


また今年のトップ10(11)のうち4枚が東京都稲城市からのエントリーとなりました。稲城市は有名なガンダムのマンホールをはじめとする多くのデザインマンホールが存在しています。多くの人が稲城市のマンホールに注目している様子が伺えますし、「稲城市といえばマンホール」という大きなうねりの存在を感じます(当社調べ)。稲城市さま、今後も多くの楽しいデザインマンホールを設置していただけますよう、お願いいたします!!


そして今年の結果を見ると、ここ数年あった「新しい蓋への人気」が少し薄れていて、むしろ「設置済みの蓋が再注目されている」様子を感じます。1位の蓋が設置された戸倉町は現在は千曲市になっていますし、3位まではすべてマンホールマップ初期に投稿された画像でした。コロナ禍の影響もあったためか、日本中を旅してマンホールの写真を撮る流れに少し歯止めがかかり、自宅からマンホールマップを見て、再びマンホール探訪の旅ができる日を夢見る1年になったのかもしれません(綺麗にまとめてみました)。



最後に、2020 年はマンホールマップに2度目の大きな変更を加えてから最初の1年になりました。リニューアル当初はシステムが不安定だった時期もありましたが、今は安定した稼働を続けることができていると自負しています。現バージョンの最大の特徴の1つでもある HATOYA ブロックチェーン対応に至っては運用開始後一度も止まることなく稼働を続けていて、投稿いただいたデータの著作権情報を守り続けています。我ながら個人運用の低コストでここまでのパフォーマンスを発揮できているのは JAXA のはやぶさか、マンホールマップか、くらいじゃないかと思ってます(半分本気)。

思っていたよりもコロナが長引き、旅をしようにも充分に注意をする必要がある期間が続きますが、そんな時間をマンホールマップを見ながら思いを馳せて過ごす時間に使っていただければと思っています。2021 年もマンホールマップをよろしくおねがいします。

このブログは IBM Cloud アドベントカレンダー 2020 13日目にエントリーしています。


IBM Cloud が提供している多要素認証サービスである IBM Security Verify for Workforce IAM を使う機会がありました。簡単に各種多要素認証を実装できるサービスだったので、備忘録の意味でもまとめてみました。

【IBM Security Verify for Workforce IAM で実現できる多要素認証の種類】
まず、このサービスを有効にすることで利用できる多要素認証の要素は以下の4種類あります:
(1) ワンタイムパスワード
(2) 確認タップ
(3) SMS
(4) メール


(1) と (2) はスマホに専用アプリ(IBM Security Verify)をインストールすることで利用可能になります。(1) は同アプリ内に表示されているワンタイムパスワードを制限時間内に入力することで確認するもの、(2) は同アプリ内に通知される確認メッセージに対して「承認」のタップを行うことで確認されます。「入力の手間がない」という点ではこの (2) が最も楽な要素といえると感じています。 また (3) はスマホへの SMS に送信されたワンタイムパスワードを入力するもの、(4) は指定したメールアドレスへ送信されたワンタイムパスワードを入力するものです。(3) と (4) は専用アプリを必要としないため、古いスマホやスマホ以外の電話機でも利用可能です(メールに関しては電話機である必要もありません)。



【IBM Security Verify for Workforce IAM を使った多要素認証】
実際に多要素認証を実現するまでの大きな流れとしては、以下の2段階となります:
1. 多要素認証サービスに登録する
2. 各種ログイン時に 1. のサービスが有効になるよう設定する



少し細かく紹介すると、1. はサービスへサインインすることに加えて、多要素認証で利用する手法を登録します。具体的にはメール、電話、SMSそしてスマホ向けの専用アプリです。一般的に多要素認証で使われるのはメール、電話、SMS でコードを知らせて入力させる、という方法ですが、最後の専用アプリを使うとプッシュで知らされる通知に「承認」タップをするだけで認証が完了します。2段階目の手続きが一番楽になる方法でもあります。

2. は 1. で登録した多要素認証サービスを「どの」認証の際に使うか、という設定です。今回のブログでは
 (1) Windows へのログイン時
 (2) Linux 等への SSH ログイン時

の2種類それぞれで使う場合の設定手順を紹介します。


【IBM Security Verify for Workforce IAM の無料評価版に登録】
まずは上記 1. のサービス登録部分を行います。

IBM Security Verify for Workforce IAM のページへ行き、「無料評価版を試す」というボタンをクリックします:
https://www.ibm.com/jp-ja/products/verify-for-workforce-iam

2020103001



IBM ID でのログインが求められるのでログインします。その後、テナントサーバーのホスト名の入力が促されるので、ユニークな(他の人が使ってなさそうな)文字列を入力して "Create tenant" ボタンをクリックします。基本的に作業はこれだけです:
2020103002


試用アカウントの作成等、色々準備が進んでいくので少し待ちます:
2020103003


1~2分程度で「ようこそ」画面が表示されます。使用条件同意にチェックを入れて「続行」:
2020103004


すると IBM Security Verify のダッシュボード画面が表示されます。これで IBM Security Verify のアカウントが作成できました:
2020103005



【IBM Security Verify for Workforce IAM に API client を登録】
サービスへのサインアップはこれだけで完了です。次に各種クライアントからこのサービスを利用できるよう、IBM Security Verify for Workforce IAM に API client を登録します。左上のハンバーガーメニューから "Configuration" を選択します:
2020112601



Configuration の "API access" タブを選択し、"Add API client" ボタンをクリックします:
2020112602


API Client を追加するダイアログが表示されます。まず適当な名前(例 MFA-Client)を入力して、Enabled がチェックされていることを確認します(まだ Save を押さずに下にスクロールします):
2020112603


そのまま下にスクロールして、Access 欄で以下の4つにチェックを入れ、最後に Save をクリックします:
- Authenticate any user
- Read authenticator registrations for all users
- Read second-factor authentication enrollment for all users
- Read users and groups

2020112604


1つ前の画面に戻り、作成した API client が一覧に表示されていることを確認します。この一覧の右側に EDIT ボタンがあるのでここをクリックします:
2020112605


クリックすると、この API client の Client ID と Client secret を確認することができます。後ほど使うのでメモしておきます:
2020112606


【IBM Security Verify for Workforce IAM にユーザーを登録】
次に IBM Security Verify for Workforce IAM に2要素認証を行うユーザーを登録します。左上のハンバーガーメニューから "Users & groups" を選択します:
2020112607


まだユーザーが登録されていない初回は最初にユーザー登録ダイアログが表示されます。以下を指定して(他は適当に指定して)Save をクリックします:
- Identity source : Cloud Directory
- user name : (これから作成するユーザーのログイン時のユーザー名)
- Work e-mail : (これから作成するユーザーのメールアドレス、この後ここにメールが送信される)
- Mobile number: (これから作成するユーザーの携帯電話番号、日本の携帯電話であれば +81 を付け、更に最初の 0 を消して登録する。このあと SMS 認証で利用する)

2020112608


ここまで完了したら(次に新規ユーザーでサインインできるよう)このアカウントではいったんサインアウトします。画面右上のアイコンから "Sign out" を選択します:
2020112609


サインアウトできました:
2020112610



【IBM Security Verify for Workforce IAM にユーザーのデバイス(スマホ)を登録】
ここからは登録されたユーザーによる作業となります。

先ほどユーザー作成時に指定したメールアドレスの受信ボックスを確認してください。IBM Security から Account created というサブジェクトのメールが送信されているはずです。その中に user name で指定したログイン名と初期パスワードが表示されています。下の URL をクリックしてログインします:
2020112611


ログイン画面が表示されたら、メールに記載されていた user name と password を指定してログインします:
2020112612


最初の1回目は初期パスワードから別のパスワードへ変更する必要があるので、自分で管理できるパスワードに変更してください:
2020112613


全て完了すると登録したユーザーで IBM Security Verify にログインします:
2020112614


次のこのユーザーのスマートフォンと、認証デバイスを登録します。画面右上のアイコンをクリックして、"Profile & settings" を選択します:
2020112615


まず登録したユーザー情報のメールアドレスや電話番号が正しいものかどうかをを確認するための画面が表示されます。確認方法は選択できますが、今回は SMS(Text message) を使って確認することにします。"Text message" の横にある "Send code" をクリックします:
2020112616


すると登録時に指定した電話番号に SMS でコードが届きます。そのコードを認証画面内に登録して Submit します:
2020112617


正しいコードを入力することができると携帯電話の登録が完了します。一応これだけでも利用できるのですが、専用アプリを登録しておくと2段階認証時の手続きが簡単になるので、続けて専用アプリを登録しておきます。"Add new method" と書かれた箇所をクリックします:
2020112618


登録するデバイスを選択する画面になります。ここでは IBM Verify app 横の "Add device" をクリックします:
2020112619


スマートフォンに "IBM Verify" アプリケーションをインストールするよう求められます。App Store や Google Play から "IBM Verify" を検索してアプリをインストールしてください。インストールできたら "Connect your account" を選択します:
2020110404


画面に QR コードが表示されます。この QR コードをスマホにインストールした IBM Verify を開いて Q読み取ります:
2020110405


デバイスが登録されますが、まだ "Unauthorized" という扱いになっています。アプリケーションの認証コードを入力してこのアプリケーションとデバイスを認証します:
2020110406


成功するとこのような画面になります:
2020110407


"Authentication app" として表示されていれば成功です:
2020110408



ここまでの作業で上記 1. の多要素認証サービスへの登録作業が完了しました。

ここから下は 2. の作業になります。実際に多要素認証を利用する認証方法ごとに行います。



【Windows へのログイン時に多要素認証を行う場合】
Windows へのログイン時に多要素認証を行う場合の作業手順を説明します。
そのための作業として、対象の Windows PC に IBM Security Verify for Windows Login という Windows アプリケーションを導入します。

まず IBM Security Verify for Windows Login の動作に必要な VSVC++ ランタイムをダウンロードしてインストールします:
https://support.microsoft.com/ja-jp/help/2977003/the-latest-supported-visual-c-downloads

2020113002



続いて以下から IBM Security Verify Gateway for Windows Login をダウンロードします:
https://exchange.xforce.ibmcloud.com/hub/IdentityandAccess

2020113001


ダウンロードしたファイルを展開し、setup.exe を実行してインストールします:
2020113003


インストール後、C:\Program Files\IBM\WindowsLogin\ フォルダ以下にある config.json.sample ファイルをテキストエディタで開きます:
2020113004


以下の内容で書き換え、config.json という名前で保存します:
{
    "ibm-auth-api":{
        "client-id":"********",
        "obf-client-secret":"XXXXXXXXXXXX", /* See obfuscate.exe tool. */
        "protocol":"https",
        "host":"xxxxxxx.verify.ibm.com",
        "port":443,
        "max-handles":16
    },
    "credential-provider":{
        "username-format":"%U",
        /*"trace-file":"c:/tmp/credprov.log", */
        "disable-builtin-password-logon": false,
        "no-mfa-account": "XXXXXXXX\\Administrator",
        "auth-method":"winpwd-then-choice-then-otp"
    }
}

上記を編集する際の注意点があります。

まず client-id には上述の作業で API client を登録した際に取得した Client ID の値をそのまま入力します。

obf-client-secret の値は少し手順が必要です。config.json.sample と同じフォルダに obfuscate.exe というコマンドラインツールがあります。コマンドプロンプトを開いて、以下のコマンドを実行します:
> obfuscate (API client を登録した際に取得した Client Secret の値)

この実行結果として表示される内容を上記 obf-client-secret の値として入力してください(Client Secret の値をそのまま入力するわけではない点に注意してください)。

そして host は IBM Security Verify for Workforce IAM サインアップ時に指定した tenantId を使った "{tenantId}.verify.ibm.com" という値を指定します。

更に username-format の値には "%U" を、no-mfa-account の値にはこの Windows PC の名前(XXXXXXX)を使って "XXXXXXX\\Administrator" と指定してください(最後の設定により Administrator アカウントのみ多段階認証が無効になります)。


最後にこのファイルを同じフォルダ内に config.json という名前で保存すれば準備完了です。

では実際に Windows で多要素認証が有効になっているかどうかを確認します。Windows のログイン画面で Administrator アカウント以外のユーザーを指定します。するとパスワード入力画面に "Sign-in options" というメニューが現れます:
2020120601


同部分をタップして開き、盾のようなアイコンを選択します(選択されていることを確認します):
2020120602


この状態でまずは普通にログインパスワードを入力します:
2020120603


すると2要素目の認証方法を聞かれます。どれを選択してもいいのですが、ここではメールアドレスを選択してみます:
2020120604


すると登録したメールアドレスに IBM Security からメールが届きます。その中にワンタイムパスワードが含まれています:
2020120605


メール内のパスワードをログイン画面に入力して再度 submit します:
2020120606


2要素認証を経て Windows にログインできました:
2020120607



【Linux への SSH ログイン時に多要素認証を行う場合】
Linux へ SSH でログインして作業する機会は珍しくないと思いますが、そのログインを2要素認証にすることも可能です。その手順を紹介します。なおここでは Linux 向け手順を紹介しますが、同様にして AIX 版を利用することで AIX へ適用することも可能です。

前提として、上述の 1. の手続き(IBM Security Verify for Workforce IAM へのサインアップとユーザー&デバイスの登録)まで済ませておきます。また今回の作業を行う対象となる Linux サーバーを用意します(SSH 可能な状態でセットアップします)。

続いて以下から IBM Security Verify Gateway for Linux PAM をダウンロードします:
https://exchange.xforce.ibmcloud.com/hub/IdentityandAccess

2020120608


対象の Linux に root でログインし、以下の手順でパッケージを展開し、インストールします:
# unzip IBMSecurityVerifyGatewayForLinuxPAM_v1.0.3.zip

# cd IBMSecurityVerifyGatewayForLinuxPAM_v1.0.3

# unzip centos7.zip (CentOS 7 or 8 の場合)

# rpm -ivh *.rpm

同パッケージが正しく動作するようデーモンを設定します。vi などのテキストエディタで /etc/pam_ibm_auth.json を編集します:
{
  "ibm-auth-api": {
    "client-id": "********",
    "obf-client-secret": "XXXXXXXXXXXX",
    "protocol": "https",
    "host": "xxxxxxx.verify.ibm.com",
    "port": 443,
    "authd-port": 12,
    "max-handles": "16"
  },
    :
}

↑具体的には上述の IBM Security Verify for Windows Login で指定したものと同様の設定を指定して保存します。

設定ファイルを編集したらデーモンを有効にします:
# systemctl enable ibm_authd_64.service --now

この後で ssh による多段階認証を有効にしますが、「設定が間違っていて、修正したいけど誰もログインできなくなった」という状態を避けるために多段階認証を適用しないユーザーも必要です。今回は root ユーザーは多段階認証なしにログインできるよう設定しておく例を紹介します:
# groupadd -r nomfa

# usermod -aG nomfa root

では sshd の設定も変更して、SSH 時の2段階認証を有効にします。まず /etc/pam.d/password-auth ファイルを /etc/pam.d/civ-auth-choice というファイルにコピーし、その上で /etc/pam.d/civ-auth-choice ファイルを編集します:
  :
  :
auth    requisite    pam_unix.so nullok try_first_pass
auth    sufficient   pam_ibm_auth.so auth_method=choice-then-otp exempt_group=nomfa
add_devices_to_choice transients_in_choice failmode_insecure accept_on_missing_auth_method
  :
  :

まず pam_unix.so を参照している auth から始まる行を探します。そして2列目の sufficient を requisite に変更します。そしてその直下に1行追加し、"auth    sufficient   pam_ibm_auth.so auth_method=choice-then-otp exempt_group=nomfa add_devices_to_choice transients_in_choice failmode_insecure accept_on_missing_auth_method " という行を追加して保存します。

続いて /etc/ssh/sshd_config ファイルを編集し、ChallengeResponseAuthentication で始まる行を探して、その値を yes に変更します(コメントされていたらコメントアウトします):
  :
  :
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication yes
  :
  :

この後で sshd を再起動します:
# systemctl restart sshd

sshd のプロセスは SELinux で守られていて、特定のポートを通じてのみアクセスできます。この部分も変更する必要があります:
# semanage port -a -t kerberos_port_t -p tcp 12

最後に PAM の設定をこれまでの作業内容を参照するよう変更します。/etc/pam.d/sshd を以下のように変更します:
#%PAM-1.0
auth  required  pam_sepermit.so
auth  substack  civ-auth-choice
auth  include   postlogin
  :
  :

↑"auth substack" で始まる行を探して、3列目の値を "password-auth" から "civ-auth-choice" に変更して保存します。

これで SSH の2段階認証が有効になっているはずです。動作確認のため以下のコマンドで(localhost で)SSH ログインしてみます(username 部分には存在するユーザーの名前を指定してください):
# ssh username@localhost

上述の Windows の時と同様に、パスワードを聞かれた後に2段階目の認証方法を聞かれます:
2020120601


今回は1番を選択した例を紹介します。上述の IBM Verify アプリをスマホに導入している場合に使うことができる選択肢です。1を入力すると OTP(ワンタイムパスワード)を聞かれます:
2020120602


この時点で登録したデバイスの IBM Verify アプリを起動し、このタイミングでのアクセスコード(ワンタイムパスワード)を確認します:
2020120605


表示されている有効期限内に入力できるようなタイミングを図りつつ、ワンタイムパスワードを入力します:
2020120603


正しく入力できると ssh が成功し、リモートログインが完了します(下図ではプロンプトが # から $ に変わっています):
2020120604


Linux の SSH でも2要素認証が実現できました。


【まとめ】
以上、手順含めての紹介だったこともあり、かなり長い説明になってしまいましたが、これだけの手続きで各種ログインの多要素認証が実現できることがわかりました。しかも90日間の体験版として無料提供されている機能を使って実現できたので、実際に本格導入する前の動作確認まで出来て、かなりお得なサービスであるように感じます。

今回紹介した多要素認証は Windows ログインと Linux (SSH) ログインでした。用語などで慣れないと戸惑う部分があるかもしれませんが、自分が躓いた所を中心に日本語解説資料を作るつもりで紹介しました。ぜひ皆さんにも試していただければと思っています。

※本ブログ記事は IBM Cloud アドベントカレンダー 2020 の 12/3 分にエントリーしています。


IBM Cloud のダッシュボードでユーザー権限周りの調べ物をしていると、見慣れないメニューに目が止まりました:
2020110601


「IP アドレスのアクセス制御」、と書かれています。現在の設定値は「無効」で「すべての IP アドレスからのアクセスを許可します」との説明が表示されています。 ということは、ここを「有効」にすると「アクセスできる IP アドレスに制約をかけることができる」と読めます。こんな機能があったことに気付いてなかった(苦笑)ので、この機会に実際の挙動を確認することにしてみました。

まずは準備として自分の環境での外部 IP アドレスを確認します。例えば確認くんあたりで自分の IP アドレスがどのように見えているかを調べます:
2020111601

(↑「あなたの IP アドレス」として表示されている内容を確認します)


自分の IP アドレスが分かったら、この値を使って IBM Cloud の「IP アドレスアクセス制御」を有効にしてみます。IBM Cloud にログイン後、メニューから「管理」→「アクセス(IAM)」を選択します:
2020111602


そして「アクセス(IAM)」画面の左ペインで「設定」を選ぶと「IP アドレスのアクセス制御」が変更できるようになります:
2020110601


ここの「無効」と表示されている部分をクリックすると、「IP アドレスのアクセス制御」ダイアログが表示されます。ダイアログ内では「有効」にチェックがついています。この「許可された IP アドレス」欄に先程確認した自分の IP アドレス(※)を入力し、最後に「保存」ボタンをクリックします:
2020111603


※単一の IP アドレスであればそのまま入力できます。これ以外にサブネットを指定して 192.168.0.0/16 形式で指定することもできますし、あるいは IP アドレスの範囲を指定して 192.168.0.1 - 192.168.0.100 と指定することもできます。


すると下図のように変更されました。これで IP アドレスによるダッシュボードへのアクセスが制御される状態になっているはずです(現在はアクセスが許可されている IP アドレスなので、このままダッシュボード内を操作することができます):
2020111604


確認するため一旦ログアウトします。そしてこれまで自宅の契約ネットワークから使っていた無線 LAN を、スマホのテザリング回線に切り替えます(IP アドレスが変わります)。そして、改めて IBM Cloud にログインしようとすると・・・
2020111605


無事に(?)アクセスを断られ、ログアウトするしか選択肢がない状態になりました。期待通りの挙動でした。

IBM Cloud と契約した後に、ダッシュボードを利用する人やそのネットワーク環境が限られているのであれば、その情報をここで有効にしておくことで想定していない利用者に勝手にダッシュボードを使われる、というリスクを軽減することができるようになります。会社のオフィスや固定回線の自宅からしか使わせないのであればそのネットワーク情報を登録するだけです。モバイル機器からのテザリングを許可させたいのであれば、(ネットワークの範囲を調べるのが大変そうですが)該当する IP アドレス範囲を指定できるのでダッシュボードへの不正なログインのリスクを軽減することができそうです。


詳しくは公式ドキュメントも参照ください:
https://cloud.ibm.com/docs/account?topic=account-ips#ips_account


このページのトップヘ