[FAQ 目次] [12.0 - 高度なユーザ向け] [14.0 - OpenBSD でディスクを使う]
このドキュメントの一部は、以下のドキュメントからとっている:
IPSec は、IP プロトコルファミリーに対する拡張だ。暗号セキュリティサービスを提供する。このサービスで、認証、完全性(integrity)、アクセス制御、機密性が提供される。IPSec は SSL と似たサービスを、ネットワーク層で提供して、しかもアプリケーションにはまったく透過的で、しかもずっと強力。透過的というのは、アプリケーションのほうでは IPSec を使うのに、IPSec のことを何一つ知らなくていい、ということだ。 IPSec 上ではあらゆる IP プロトコルを使える。暗号化トンネル (VPN) も作れるし、コンピュータ間で単純な暗号化をしてもいい。オプションが実にいろいろあるせいで、IPSec はちょっとややこしいのである (それも SSL よりずっと!)
IPSec を使う前に、FAQ 6章 の推奨文献には是非とも目を通しておいてほしい。特に、もし IP アドレスの考え方がわかっていなかったら、Understanding IP Addressing は大いにお奨めだ。
論理的には、IPSec は以下のどんな形でも機能する:
ネットワークのからむすべてのシナリオで、ぼくたちはルータを念頭においている。つまりは Host-to-Router (そしてこのルータは、あるNetworkのトラフィックを制御して暗号化する)。
これから見るように、IPSec は VPN 接続用にトラフィックをトンネルできる。でも、その応用は VPN よりはるかに広い。中央インターネット鍵交換登録所があれば、インターネット上の全マシンはお互いにやりとりをするときに、強力な暗号や認証が使えるようになるんだ!
インターネットのプロトコルである IP または IPv4 は、それ自体としては、転送しているデータに対して何の保護も提供しない。送り主が、自分で名乗っている通りの存在かどうかすら保証してくれない。IPSec はこれを解決しようとする。以下のサービスはそれぞれ独立と考えられているけれど、IPSec はそれを統一的な形でサポートしている。
受信者以外の人には、どんなデータが通信されたかを理解しにくいようにしておく。インターネット経由でリモートのマシンにログインするとき、ほかの人にパスワードを知られたくないよね。
データが途中で改竄されないようにする。請求書データをオンラインで送るんなら、数量や金額やアカウント番号が正確で、途中で改竄されたりしていないか確かめたいでしょう。
データに署名して、それを送ったのが本当にあなただと他の人が確認できるようにする。ドキュメントがインチキじゃないと確認できるのは、どう考えてもよいことだ。
やりとりは、何度も繰り返すよう認められたもの以外は、確実に一回だけしか生じないようにする方法が必要だ。つまり、だれかがやりとりを記録しておいて、それをそのまま再送して、結果として同じ応答を何度ももらう、ということができないようにする必要がある。たとえば、攻撃者が暗号クラック以外の手段でトラフィックの趣旨を他の方法でつきとめて、そしてそのトラフィックが、その人物にとって有利なイベントを生じさせるものとしよう(かれの口座にお金を振り込むとか)。その人物が、あとから単純に同じトラフィックを再送してもうまくいかないようにする必要がある。 警告: 通常の仕様に関する限り、手動鍵の IPsec を使っているとき (たとえば ipsecadm(8) を使っているとき) には再送からの保護は実行されない.
IPSec は、機密性、完全性、authenticity(正真性)、再送保護を提供するのに、新しいプロトコルを 2 つ使う。このプロトコルは AH( Authentication header, 認証ヘッダ)と ESP(Encapsulated security payload、暗号ペイロード)だ。
AH は認証と完全性と再送保護を提供する(が機密性は提供しない)。ESP との主な差は、AH はパケットの IP ヘッダの一部(たとえばパケットの発信元・送り先アドレス)も保護することだ。
ESP は認証、完全性、再送保護、データ機密性を提供する(ヘッダにつづくパケット内のすべてを保護する)。再送保護は認証と完全性が必要だ(この二つはいつもペアでくる)。機密性(暗号化)は、認証/完全性があってもなくても使える。同じように、認証・完全性は機密性なしでも使える。
認証ヘッダ(Authentication Header) (AH) は基本的な IP ヘッダの後にきて、データの暗号ハッシュと識別情報を持っている。ハッシュは IP ヘッダ自体の、伝送中に値が変化しない部分もカバーできる。AH に使う実際のアルゴリズムについては、いくつか別個の RFC があって選べるようになっているけれど、そのどれも、RFC2402に指定されたガイドラインには準拠していなくてはならない。
暗号ペイロード(Encapsulating Security Payload) (ESP) ヘッダは、ペイロードを暗号化された形で書き換えることを可能にする。ESP ヘッダは、それに先立つ IP ヘッダは扱わないので、ペイロード以外のものについてはまったく保証しない。それぞれ各種の ESP は RFC2406にしたがう必要がある。 ESP ヘッダは、ペイロードの認証も提供できる(が ESP の外のヘッダについては認証できない)。
IPsec 機能の(ほとんど)独立した部分が、IPSec encapsulation をやっているのがデータのもとの発信源かゲートウェイかに応じて適用される:
IPSec で保護されたリンクは、Security Associations(SAs) によって定義づけられる。各 SA は単一の単方向のデータの流れについて定義されて、普通は(マルチキャストは無視して)一つの点から別の点までについて、なんらかのユニークなセレクタによって識別できるトラフィックフローをさす。単一の SA 上を流れるトラフィックはすべて同じ扱いを受ける。トラフィックの中には、複数の SA を経るものもあって、そのそれぞれがなんらかの変換を加える。SA の集団を SA Bundle と呼ぶ。入ってくるパケットは、3 つの定義フィールド(宛先 IP アドレス, セキュリティパラメータインデックス(Security Parameter Index), セキュリティプロトコル)に応じて指定の SA に割り当てることができる。セキュリティパラメータインデックス(Security Parameter Index、略してSPI)は接続のパラメータのネゴシエーションが行われるときに、SA の受け手が手渡すクッキーだと思えばいい。セキュリティプロトコルは AH か ESP のどちらかでなくてはならない。受け手の IP アドレスがこの3つ1組の中に含まれているので、これはユニークな値になることが保証されている。これは外側の IP ヘッダから見つけることもできるし、最初のセキュリティヘッダ(これは SPI とセキュリティプロトコルを含む)から見つけることもできる。
トンネルモードの AH パケットの例を挙げよう:
IPヘッダ | AH | IPヘッダ2 | TCPヘッダ | データ |
transport モード AH パケットの例を挙げよう:
IPヘッダ | AH | TCPヘッダ | データ |
ESP ヘッダは外側の IP ヘッダを認証できないので、AH と ESP ヘッダを組み合わせて次のようにしたほうがいい:
IPヘッダ | AH | ESP | TCPヘッダ | データ |
これは Transport Adjacency と呼ばれる。トンネル版だとこんな感じだ:
IPヘッダ | AH | ESP | IPヘッダ2 | TCPヘッダ | データ |
でも、これは RFC には明示的に記述されていない。Transport adjacency と同じように、これはIP ヘッダの中のヘッダいくつかを除いて全パケットを認証したうえで、ペイロード(イタリクスで表示)を暗号化する。AH と ESP ヘッダがこのように直接いっしょに適用されているときには、ヘッダの順番は上記のようになっている必要がある。トンネルモードでは、任意の recursive encapsulation をやることで、この順番が指定されずにすむようにすることもできる。
IPSec システムとゲートウェイがどう設定されるかは、ある程度は設計者まかせになってはいるのだけれど、でも RFC はそれがどう実装されるべきかについて強いレコメンデーションを行って混乱を最小限におさえようとしている。
パケットに何が起こるかをコントロールする、管理エンティティが2つある。一つはSecurity Association Database (SAD, OpenBSDの IPSecソースコードの中では、TDB または TDB table と呼ばれている)で、もう一つはSecurity Policy Database (SPD)だ。
この二つは、あるトラフィックを表現したセレクタをいくつか与えられると、必要となる処理を記述したエントリを提供してくれるという点で似ている。でもSPD は実際の処理から二段階ほど遠いところにある: SPD は外へ出るパケットに使われて、どの SAD エントリを使うべきか決めるのに利用される。逆に SAD エントリは、実際のプロセスとそこで使うパラメータを記述する。SPD のエントリは、既存の SAD エントリのうちどれを使うか(バンドルなら、SAD エントリは複数あり得るので)を指定するけれど、でもすでに適切なものがないなら、そのエントリを使って新しいものがつくられる。つくられる SA のフィールドは、SPD エントリから持ってくる場合もあるし、そのフィールド新設を開始させたパケットから持ってくる場合もある。
外行きのパケットは、SPD エントリから個別の SA に行ってエンコーディング用パラメータをもらう。入ってくるパケットは、SPI/宛先IP/プロトコルの 3 点セットを使って直接正しい SA にたどりつき、そこから SPD エントリにたどりつく。
SPD はまたどのトラフィックが IPSec をバイパスすべきか、またどのトラフィックを捨てるべきかを指定できるので、入ってくる非 IPSec のトラフィックについても参照されなくてはならない。SPD エントリは、順番が明示的に示されている必要がある。あるパケットに複数のものがマッチする可能性があるし、処理には再現性がなくてはならないからだ。
SPD というのは、パケットフィルタと似たようなものだと思えばいいかもしれない。そこで決定されるアクションというのは、SA プロセスの起動になるわけだ。セレクタとして使えるのは 送信元と宛先アドレス、関係ある場合にはポート番号、アプリケーションや、ある場合にはユーザ ID (これは host based transport SAのみ)、ホスト名、セキュリティ感度レベル、プロトコルなどだ。
SAD エントリに含まれるのはたとえば:
SPD エントリに含まれるのは:
各 SA は、ESP ヘッダ一つと AH ヘッダ一つを定義できる。IPSec セッションはこのどちらか、あるいは両方を持たなきゃならない。どちらのヘッダもなしで定義されることはできない――さもないと、SA を参照するための SPI を指定するヘッダがないことになってしまう。RFC は、AH とESP ヘッダが SPI の値について別々の指定をしている場合のことは定義していない。察するに、これはバンドル中の複数の SA を意味するものと判断されるだろう。
OpenBSD の SPD は、ipsecadm flow コマンドを使って管理される(これに変更を加えるのは、手動鍵設定を使う場合だけだ)。SAD エントリは、 ipsecadm(8)を使えばマニュアルで設定できるけれど、IETF はセッションや鍵交換の初期化などの自動メカニズムも定義している。 OpenBSD はPhoturis (RFC2522および RFC2523) と ISAKMP 自動かぎ交換 (RFC2407, RFC2408, and RFC2409) を実装していて、それぞれ photurisd(8) と isakmpd(8) デーモンで使われている。
IPSecの手始めとしていちばんかんたんなのが手動鍵設定だ。この手法でネットワーク間を暗号化してVPNをつくれる。この部分を読んだら、この設定を自動化するのに/usr/share/ipsec/rc.vpnを使う、なんていうのもやってみるといいかもしれない。
まず、OpenBSDカーネルの IP AH と IP ESP オプションを有効にしよう (もし rc.vpn スクリプトを使っていたり、あるいはこの次の例のように、ESP だけを使っているような場合には AHは有効にしないでいい。それどころか、使っていないのに AH を有効にするとセキュリティ上の問題が発生するかもしれない)。
こういうプロトコルを有効にするための、すてきな sysctl がある。
# sysctl -w net.inet.esp.enable=1
net.inet.esp.enable: 0 -> 1
# sysctl -w net.inet.ah.enable=1
net.inet.ah.enable: 0 -> 1
起動時にこれをたちあげるには/etc/sysctl.conf を編集すればいい。 使いたいものに応じてnet.inet.esp.enable そして/あるいは net.inet.ah.enableの前の # をはずし、それが 1 にセットされていることを確かめよう。
さらに手動鍵の生成も必要だ。VPN のセキュリティは、この鍵を推定するのが不可能だという点にかかっているので、この鍵を選ぶのには強力な乱数源を使うのがとてもだいじだ。これを生成するのに実用性が高い方法の一つとして、random(4)デバイスを使う手がある。たとえば160ビット分の乱数性をつくりだすには、以下のようにする:
# dd if=/dev/urandom bs=1024 count=1 | sha1
生成されるビット数はだいじだ。暗号の種類によって、必要な鍵のサイズがちがう。
暗号方式 鍵長 DES 56 bits 3DES 168 bits BLF 可変 (40-160, 160 bits 推奨) CAST 可変 (40-128, 128 bits 推奨) SKIPJACK 80 bits
では、SA (Security Associations) の設定をしよう。Security Association というのは、IP アドレス、SPI, セキュリティプロトコル (AH そして/または ESP) の組み合わせだ。IP アドレスは、あなた自身のものと、送り先のもの両方だ。SPI (Security Parameter Index) は各種 SA の分類に OpenBSD が使う番号だ。
これらの例は、トラフィックの暗号化に ESP しか使わない。ESP は暗号化された中身のデータの認証はするけれど、AH とはちがってそれを包むIP ヘッダは認証してくれない。この「限られた認証」は、それでもほとんどの場合にはまったく十分なものだ。特にトンネル環境での ESP の場合には。
# ipsecadm new esp -spi SPI_OUT -src MY_EXTERNAL_IP -dst PEER_EXTERNAL_IP -forcetunnel -enc blf -auth sha1 -key ENC_KEY -authkey AUTH_KEY
これを二つのルータで実際にやってみよう。ルータのIPアドレスはそれぞれ192.168.5.1 と 192.168.25.9だ。
ホスト192.168.5.1上では:
# ipsecadm new esp -spi 1000 -src 192.168.5.1 -dst 192.168.25.9 -forcetunnel -enc blf -auth sha1 -key 7762d8707255d974168cbb1d274f8bed4cbd3364 -authkey 6a20367e21c66e5a40739db293cf2ef2a4e6659f
# ipsecadm new esp -spi 1001 -dst 192.168.5.1 -src 192.168.25.9 -forcetunnel -enc blf -auth sha1 -key 7762d8707255d974168cbb1d274f8bed4cbd3364 -authkey 6a20367e21c66e5a40739db293cf2ef2a4e6659f
ホスト 192.168.25.9上では:
# ipsecadm new esp -spi 1001 -src 192.168.25.9 -dst 192.168.5.1 -forcetunnel -enc blf -auth sha1 -key 7762d8707255d974168cbb1d274f8bed4cbd3364 -authkey 6a20367e21c66e5a40739db293cf2ef2a4e6659f
# ipsecadm new esp -spi 1000 -dst 192.168.25.9 -src 192.168.5.1 -forcetunnel -enc blf -auth sha1 -key 7762d8707255d974168cbb1d274f8bed4cbd3364 -authkey 6a20367e21c66e5a40739db293cf2ef2a4e6659f
ごらんのように、SPI がちがっている。SPI が何で、それがどこで使われているかについての完全な説明は、On the wire format を参照。
これで Security Associations ができあがったので、フローを設定しよう。
さてここでいきなり、フローが2つ創られる。一つはローカルのソースアドレスで、ローカルホストから出て目的地に向かうすべてのパケットをカバーし、もう一つのフローは送り先からローカルホストに戻ってくるフローだ。
# ipsecadm flow -proto esp -dst 192.168.25.9 -spi 1000 -addr 192.168.5.1 255.255.255.255 192.168.25.9 255.255.255.255
# ipsecadm flow -proto esp -dst 192.168.5.1 -spi 1001 -addr 192.168.25.9 255.255.255.255 192.168.5.1 255.255.255.255
もし Host-to-Host VPN のオーバーヘッドを減らしたければ、SPI を作るのに -forcetunnel をはずしておくと、transport モードが使える (-forcetunnel を使うと IP ヘッダまで含んだIP パケットのすべてが必ずSPIにカプセル化される)。もし発信元か送り先のどちらかがネットワークなら、トンネルモードを使うしかない。ネットワークから出入りするトラフィックに SA を使うと、自動的にトンネルモードの SPI が確実に作られることになる。
これはIPSecを使い始める簡単なやりかただ。
IPSec を使えば、プライベート IP アドレス空間をインターネットごしにつなげる。いい例を挙げよう……208.1.1.1の背後にある 192.168.99.0/24 と、208.2.2.2の背後にある 208.1.5.0/24 をトンネルでつなげたいとしよう。以下の例は rc.vpn スクリプトを使って生成したものだ。
ごらんのとおり、IPSecで手動鍵設定を使っていると、やってほしいことをずばり正確に指定しなきゃダメだ。あなたのかわりに見当をつけてくれたりはしない。以下の例をみてごらん……
まず、security associations (SA)を設定しよう:
(これで SPI, 暗号化の方法と鍵が設定される)
# ipsecadm new esp -src 208.1.1.1 -dst 208.2.2.2 -forcetunnel -spi 1001 -enc blf -auth sha1 -key 7762d8707255d974168cbb1d274f8bed4cbd3364 -authkey 67e21c66e5a40739db293cf2ef2a4e6659f
# ipsecadm new esp -src 208.2.2.2 -dst 208.1.1.1 -forcetunnel -spi 1000 -enc blf -auth sha1 -key 7762d8707255d974168cbb1d274f8bed4cbd3364 -authkey 67e21c66e5a40739db293cf2ef2a4e6659f
次に、208.1.1.1 から 208.2.2.2へのフローを設定:
# ipsecadm flow -proto esp -dst 208.2.2.2 -spi 1001 -addr 208.1.1.1 255.255.255.255 208.2.2.2 255.255.255.255
次に 208.2.2.2の背後にある208.1.2.0/24 から 192.168.99.0/24へのフローを設定:
# ipsecadm flow -proto esp -dst 208.2.2.2 -spi 1001 -addr 192.168.99.0 255.255.255.0 208.1.2.0 255.255.255.0
次に 208.2.2.2の背後にある 208.1.5.0/24 から 192.168.99.0/24へのフローを設定:
# ipsecadm flow -proto esp -dst 208.2.2.2 -spi 1001 -addr 192.168.99.0 255.255.255.0 208.1.5.0 255.255.255.0
こんどは 208.2.2.2の背後にある 208.1.2.0/24 からルータ 208.1.1.1へのフローを設定:
# ipsecadm flow -proto esp -dst 208.2.2.2 -spi 1001 -addr 208.1.1.1 255.255.255.255 208.1.2.0 255.255.255.0
オッケー、では 208.2.2.2の背後の 208.1.5.0/24 からルータ 208.1.1.1へのフローを設定
# ipsecadm flow -proto esp -dst 208.2.2.2 -spi 1001 -addr 208.1.1.1 255.255.255.255 208.1.5.0 255.255.255.0
最後に、ルータ 208.2.2.2 から 192.168.99.0/24へのフローを設定しよう
# ipsecadm flow -proto esp -dst 208.2.2.2 -spi 1001 -addr 192.168.99.0 255.255.255.0 208.2.2.2 255.255.255.255
前と同じように、まずは SAの設定から……
# ipsecadm new esp -src 208.2.2.2 -dst 208.1.1.1 -forcetunnel -spi 1000 -enc blf -auth sha1 -key 7762d8707255d974168cbb1d274f8bed4cbd3364 -authkey 67e21c66e5a40739db293cf2ef2a4e6659f
# ipsecadm new esp -src 208.1.1.1 -dst 208.2.2.2 -forcetunnel -spi 1001 -enc blf -auth sha1 -key 7762d8707255d974168cbb1d274f8bed4cbd3364 -authkey 67e21c66e5a40739db293cf2ef2a4e6659f
さてこっちは裏返しになるので……ルータ 208.2.2.2 から 208.1.1.1へのフローを設定:
# ipsecadm flow -proto esp -dst 208.1.1.1 -spi 1000 -addr 208.2.2.2 255.255.255.255 208.1.1.1 255.255.255.255
208.1.1.1の背後にあるネットワーク 192.168.99.0/24 から 208.1.2.0/24へのフローを設定:
# ipsecadm flow -proto esp -dst 208.1.1.1 -spi 1000 -addr 208.1.2.0 255.255.255.0 192.168.99.0 255.255.255.0
208.1.1.1の背後にあるネットワーク 192.168.99.0/24 から 208.1.5.0/24へのフローを設定:
# ipsecadm flow -proto esp -dst 208.1.1.1 -spi 1000 -addr 208.1.5.0 255.255.255.0 192.168.99.0 255.255.255.0
では208.1.1.1の背後の 192.169.99.0/24 からルータ 208.2.2.2へのフローを設定:
# ipsecadm flow -proto esp -dst 208.1.1.1 -spi 1000 -addr 208.2.2.2 255.255.255.255 192.168.99.0 255.255.255.0
はーい、もうすぐおしまいですよー……
208.1.2.0/24 と 208.1.5.0/24 をルータ 208.2.2.2から 208.1.1.1まで届けるのに、あとフロー2つだけ:
# ipsecadm flow -proto esp -dst 208.1.1.1 -spi 1000 -addr 208.1.2.0 255.255.255.0 208.2.2.2 255.255.255.255 -ingress
# ipsecadm flow -proto esp -dst 208.1.1.1 -spi 1000 -addr 208.1.5.0 255.255.255.0 208.2.2.2 255.255.255.255 -ingress
ipsecadm を使っていて、自分のやった作業をぜんぶご破算にして一からやりなおしたければ、次のようにする:
# ipsecadm flush
これですべての IPSec 情報 (SPI、フロー、ルーティングのエントリ)がシステムから一掃される。
Photuris はまだあまり使われていないし、RFCのステータスから言えばまだ実験段階だ。でもOpenBSDではたくさんの人が利用してきた。
photurisd を設定するには、まず /etc/photuris/secrets.conf を photurisdを持ったホストのすべてで編集すること。
bsd# cat /etc/photuris/secrets.conf # Accepted keywords are: # identity local "id" "secret" # identity pair local "receivedid" "myid" "secret" # identity remote "id" "secret" # identity lookup "tag" username # Simple identity local "Default" "ここを変える" identity remote "Default" "ここを変える"
"ここを変える" の部分を、local config 側で好きな鍵にして、それからremote configでは別の好きな鍵にしよう。 (リモートボックスでも config を使うこと。ただし "local" "remote" を入れ替えて、リモートホスト側にとってはそっちがローカル鍵になるようにする。) なお、これらの鍵は将来の photurisd のバージョンでは、最初の鍵交換を公開鍵で行うような形で置き換わることになるので注意。
net.inet.ah.enable が 1に設定されていることを確認しよう。
bsd# sysctl -w net.inet.ah.enable=1 net.inet.ah.enable: 0 -> 1
それから startkeyを実行。
bsd# startkey dst=remote.host
それでは tcpdump を実行して、パケットが AHで暗号化されていることを確認してみよう(別のウィンドウでpingするとか、なんかセッションを開始してトラフィックをつくること)。
bsd# tcpdump proto ah
なにも出てこないようなら、tcpdump をホストアドレス側で使ってみる手がある。
bsd# tcpdump host remote.host
photurisd が自動的に発信元と送り先のホストやネットワークを設定するようにするには、 /etc/photuris/photuris.startupに記述しておく。
VPNs をはじめIPSecの各種伝統的なアプリケーションを考えているなら、たぶん ISAKMP を使うことになる。IPSec の商業実装の一部は、手動鍵設定をさせてくれないので、なんらかの形の ISAKMPを使うしかなくなる。
ISAKMP (ときどき IKE, Internet Key Exchange、インターネット鍵交換、自動鍵交換とも呼ばれる) は VPN 用の鍵交換メカニズムだ。RFC 2407, RFC 2408、RFC 2409に記述された手法を使ってセキュリティ上の問題をクリアしている。ISAKMP は、通常なら ipsecadm(8)を使わなくてはならないような暗号家具のやりとりを管理してくれる。 二つのIPSecノード間でIPSecパラメータを確立するために、二段階プロセスを採用している。
フェーズ 1 - ISAKMP ピア2つは、保護され認証されたチャネルを確立し、2つのデーモン間で通信ができるようにする。これは両ホスト間で Security Association (SA) を確立する。このチャネルを確立するための手法は、Main Mode と Aggressive Mode だ。Main Mode は各種認証情報を特定の順番で送り、アイデンティティの保護を提供する。Aggressive Mode はアイデンティティ保護は提供しない。認証情報をすべて一気に送るからだ。Aggressive mode を使うのは、ネットワークの帯域幅が狭いときだけにしたほうがいい。
フェーズ 2 - Security Associations がIPSecにかわってネゴされる。フェーズ 2 はIPSecホスト間にトンネルか endpoint SA を確立する。フェーズ 2 ではQuick Mode が使われる。フェーズ 1 ですでに SA が確立しているので、完全な認証をくり返さなくていいからだ。
手短にいえば、フェーズ 1 は保護されたチャネルを確保するのに使われて、そこで(もっと手早い)フェーズ 2 の設定が行われる。同じフェーズ 1 チャネルの中で、複数のフェーズ 2 設定をすることもある。フェーズ 2 は実際のトンネルを設定するのに使われる。フェーズ 1 では IPSec ノード同士が接続を確立して認証を交換する (X509 証明か、事前に共有した秘密)。これで両端とも、相手が認証されたことを確認できる。フェーズ 2 は鍵の交換で、両者の間のデータがどう暗号化されるかを決める。
デフォルトで OpenBSD は ISAKMP とIPSec スタック用のバイナリがついてくる。残念ながら、サンプルファイルはデフォルトではない。これを手に入れるには、ソースツリーから以下のものを取ってこよう:
CD-ROM(当然持ってるよね)からでもいいし、cvsweb やコマンドライン CVS クライアント を使ってもいい (Cvsweb は VPN-east.confと policy を用意してある)。この例で使うには、policy を /etc/isakmpd.policy にコピーしよう。VPN-east.conf は /etc/isakmpd/isakmpd.confにコピーする。ここでは、VPN (トンネル) の設定の仕方を説明してみる。もし isakmpd を個別ホスト間で使いたければ、samples ディレクトリにそれ用のサンプルが入っている。manページに詳しい情報があるので、 isakmpd.conf(5) と isakmpd.policy(5)をお忘れなく。
まずは esp の起動からだ。13.6の頭のところ で、これを実行時・起動時にそれぞれやる方法を説明している。次に /etc/isakmpd.policy の編集だ。このファイルは ISAKMP に、だれが IPSec にアクセスできるかを教える。このシナリオでは、この policy ファイルは、Encapsulate Security Payload(ESP)を使ってデータを送ってきて、mekmitasdigoat というパスワード(これはあなたが勝手に決めればいい)で認証された相手なら、だれでも isakmpd と通信できると述べている。このファイルをを変更して、特定のデジタル証明書で署名されたデータだけを認めるとか、特定の暗号変換を使ったデータだけを認めるとか、希望をISAKMPに伝えられる。まただれでも IPSec が使えるようにしてもいい。これはテスト用だけにしておくのが望ましい。万人にアクセスさせるには、policy ファイルを編集して以下だけにしよう:
KeyNote-Version: 2 Authorizer: "POLICY"
同じ policy ファイルには $ のついた行が二行ある。使う前にこの2行は削除すること。CVS でしか使わない。
この例で、もっと使い物になる policy ファイルはこんな感じだ:
KeyNote-Version: 2 Comment: この policy は正しいパスワードを使うリモートからの ESP SA を受け付ける Authorizer: "POLICY" Licensees: "passphrase:mekmitasdigoat" Conditions: app_domain == "IPSec policy" && esp_present == "yes" -> "true";
これを実装すれば、ESP だけを使った基本的な VPN (トンネル) ができあがる。ホスト A では /etc/isakmpd/isakmpd.conf を編集する。見本で入っている249.2.2.2 という IP アドレスは、ホスト A の実際の外部 IP アドレスに書き換えること。
[General] Retransmits= 5 Exchange-max-time= 120 Listen-on= 249.2.2.2
同じようなことをホスト B の isakmpd.conf でもやろう。249.3.3.3 はホスト B の外部 IP アドレスだ。
[General] Retransmits= 5 Exchange-max-time= 120 Listen-on= 249.3.3.3
ここで isakmpd のおもなふるまいを決める変数を設定できる。ここではデフォルトを使っておけばいい。Listen-on= value は、isakmpd が聞き耳をたてるべき IP を指定する。あなたのゲートウェイのインターネット IP だけが必要だ。ゲートウェイに複数の外部インターフェースがあるなら、コンマで区切った一覧形式で入力して、どのインターフェースを聴いてほしいか一覧にできる。
次にホスト A で、もう一度isakmpd.conf を編集しよう。
[Phase 1] 249.3.3.3= HostB
ホスト Bでは:
[Phase 1] 249.2.2.2= HostA
この部分は、フェーズ 1 接続のネゴシエーションをするときに受け付けるべき IP アドレスを記述する。ここでの値は下の部分を指している(フェーズ 1 は単にリモートのピアを認証して、それが主張通りの相手だと確認するだけなのをお忘れなく)。 IP_Address= <PEER-NAME>という形式で複数のピアを記述できる。
次にホスト Aでは:
[Phase 2] Connections= HostA-HostB
ホスト Bでは:
[Phase 2] Connections= HostB-HostA
これは接続のフェーズ 2 を記述したもの。このフェーズは、通信に両ピアが使うプロトコルを決めるところだ。
Connections= tag は、その下のセクションをさす。フェーズ 2 を設定するために受け入れられるメソッドや要件をイニシエートする。これはまた、いったん開始したらどの接続をイニシエートすべきかを ISAKMPD に告げる。複数のピアホストにつなぐつもりなら、以下のように複数のセクションを書いてもいいことに注意。
リモートホストの IP アドレスがわからなければ、 Connections= tag に挙がっていない IP からの接続で参照される、汎用エントリをあるセクションに記述しておいて、それを Default= で指定するようにすればいい。
ホスト Aでは:
[HostB] Phase= 1 Transport= udp Local-address= 249.2.2.2 Address= 249.3.3.3 Configuration= Default-main-mode Authentication= mekmitasdigoat #Flags=
ホスト Bでは:
[HostA] Phase= 1 Transport= udp Local-address= 249.3.3.3 Address= 249.2.2.2 Configuration= Default-main-mode Authentication= mekmitasdigoat #Flags=
これらは上で説明したフェーズ 1 の部分で参照されているセクションだ。それぞれフェーズ 2 に進むためにピアのゲートウェイが満足しなければならない要件を記述している。ほかにもオプションはたくさんあるけれど、上に挙げたものは最低限必要なものだ。
ホスト Aでは:
[HostA-HostB] Phase= 2 ISAKMP-peer= HostB Configuration= Default-quick-mode Local-ID= Net-A Remote-ID= Net-B
ホスト Bでは:
[HostB-HostA] Phase= 2 ISAKMP-peer= HostA Configuration= Default-quick-mode Local-ID= Net-B Remote-ID= Net-A
これらは、上記のフェーズ2で参照されているセクションをあらわしている。これは個別の接続のために、二つのゲートウェイ間で話をするのに ISAKMPD が使うべき個別設定なのだ。
ここはIPSec-ID セクションだ。以下のエントリは、ホストAとホストBの両方で isakmpd.conf ファイルの中になければいけない。この例だとホストA(これは上の Net-Aにつながっている)では 192.168.1.0/255.255.255.0 、ホストB(これは上の Net-Bにつながっている)では192.168.20.0/255.255.255.0 だ。
[Net-A] ID-type= IPV4_ADDR_SUBNET Network= 192.168.1.0 Netmask= 255.255.255.0 [Net-B] ID-type= IPV4_ADDR_SUBNET Network= 192.168.20.0 Netmask= 255.255.255.0
この二つのセクションが各ホストの conf ファイルに含まれている。これがLocal-ID と Remote-IDの識別しで参照されるセクションだ。一つのプライベートネットワークから、別のプライベートネットワークへのトラフィックを可能にするのに設定されるべき経路と記述している。 ID-type= は IPV4_ADDR_SUBNET か IPV4_ADDRがとれる (RFC2708 にはほかにも有効な値があがっている。OpenBSDの実装ではいまのところIPv4 しかサポートされていない。IPv6 は、OpenBSD-current でサポートされているかもしれない)。
これで両方のホストで、sample ファイルはこんな具合になっているはずだ:
[Default-main-mode] DOI= IPSEC EXCHANGE_TYPE= ID_PROT Transforms= 3DES-SHA
このセクションはフェーズ 1 接続で使う暗号方式の要件を記述している。名前は Configuration= 変数のとる値を反映している。ごらんのとおり、 Domain of Interest (DOI) を IPSEC として記述した。EXCHANGE_TYPE 変数は、フェーズ 1 では ID_PROT に設定してある、これはこの認証でカバーされるプロトコルを指定している。 Transforms= はこのやりとりで必要とされる(または指定される)暗号変換方式だ。この例では、これは設定ファイルの下のセクションをさしていて、そこでは、われわれは3DESで暗号化されていてSHAで確認できるチェックサムを持つパケットを受け取る、と書いてある。サンプルのVPN-east.confには、いろいろ変換方式が山ほどかいてある。なぜかというと 3DES や SHA は各種プラットホームで必ずしもサポートされいるわけではないからだ。OpenBSD の場合、これを基本的な設定で変えるべき理由は特にない。このセクションをコピーして変換方式を変えるのは、ぞんぶんにやってほしい。唯一、必要になるのは、 Configuration= 変数も変えることだ。
[Default-quick-mode] DOI= IPSEC EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-3DES-SHA-PFS-SUITE,QM-ESP-DES-MD5-PFS-SUITE
このセクションは、VPN経由で送られるデータの暗号の要件を記述するところで、上の Configuration で参照される。このセクションと、すぐ上のフェーズ 1 でここに相当するところとのちがいは、 EXCHANGE_TYPE が QUICK_MODEになっていることなのに注目。フェーズ 2 では必ずこうなる。 Suites= は IPSec Suite セクションを指している。両ホスト間で提供されている各種の暗号方式を記述したものだ。ISAKMP と IPSec については、ほかにも説明することがいっぱいある。いまの基本的な説明をもとに、自立してやっていける単純ながらも堅牢なVPNができる。でもこれは、両ホストにとって必要最低最小限の isakmpd.conf でしかない。
最初にこのデーモンを走らせるときには、以下のコマンドを使おう:
# isakmpd -d -DA=99
デーモンはデーモンモードでは走らず、ふつうのプロセスとして走る。そしてすべてをターミナルに出力する。isakmpdを止めて経路を一掃するには、各ノードでisakmpd プロセスを殺してから ipsecadm flushを実行しよう。
事前に共有した鍵のかわりに証明書を使うように isakmpd を設定するのは、保護されていないピアがたくさんある巨大ネットワークの場合には、小さなネットワークにくらべてそんなにむずかしくない。むしろ設定が簡単になって、さらに重要なこととして鍵管理も簡単になるかもしれない。
鍵や証明書の生成の仕方についてのよい記述が、isakmpd ソースディレクトリの README.PKI ファイルに書いてある。必要なのは CA 鍵、対応する CA X.509 証明書、ネットワーク上の isakmpd を使うコンピュータそれぞれに秘密鍵一つと、その秘密鍵のそれぞれに対して X.509 証明書一つずつだ。
X.509 証明書は、証明書の持ち主を記述する Subject Alternative Name (SubjectAltName) extension が必要だ。証明書の SubjectAltName extension を certpatch を使って設定する方法も、SubjectAltNameとしてIPアドレスを設定する場合の説明が README.PKI に書いてある。ここで IP アドレスを使うのは、isakmpd のデフォルトのふるまいでもある。
Certpatch はまた、 FQDN (Fully Qualified Domain Name) か UFQDN (User FQDN) の使用もサポートしている。FQDN の例はたとえば www.openbsd.org だし、UFQDN の例としてはメールアドレスがある。たとえば Jorgen.Granstam@abc.se など。
この howto 文書では、 FQDN を SubjectAltNames で使う。IP アドレスを使うほうがちょっと簡単になる。それが isakmpd のデフォルトのふるまいだからだ。でも、すぐにわかるように大した差ではない。
FQDN SubjectAltName を証明書に入れるには、こんな感じにすればいい:
$ /usr/sbin/certpatch -t fqdn -i home.mysite.se -k ca.key originalcert.crt newcert.crt
ここで ca.key は CA の秘密鍵なので、これができるのは CA 秘密鍵にアクセスできる人だけだ。home.mysite.se というのは(実在はしないけれど)証明書に挿入されるべき FQDN だ。 originalcert.crt と newcert.crt のファイル名は同じ名前にしてもいい。この場合、もとのファイルは新しい変更済みの証明書に上書きされる。
この鍵と証明書を、README.PKI の最後に説明にしたがってディレクトリに放り込もう。もし本気で鍵を使うつもりなら、CA 鍵 (ca.key) はどこか安全なところにしまっておこう。
こんどは /etc/isakmpd/isakmpd.conf 設定ファイルを見てやろう。これはもともと isakmpd.conf(5) のサンプルファイルから取ったものだけれど、かなり書き換えてある。さらにman ページにあるものよりもかなり短いファイルを使う。この設定の理解を簡単にするために、ファイルから、この設定には必要ないものをほとんど削除した。さらにコメントも追加して(一部のコメントは isakmpd.conf(5)にあったまま) 、名前もちょっと変えた。ここで使ったドメイン名は、ぼくの知る限りでは一つも実在していない。
実はこれを読む人はみんな、すでに事前共有鍵についてまともに動く設定を持っているので(前の節を参照)このファイルでも目新しいところはあまりない。だからこれは、全部事細かに説明したりはしない。ぼくが説明しない部分については isakmpd.conf(5) を見てほしい。
全体の構成はこんな感じだとしようか。
one.mysite.se one.worksite.se 192.168.1.2--+ 10.0.0.1====/======10.0.0.2 +--192.168.2.2 | gw.mysite.se gw.worksite.se | +--192.168.1.1 192.168.2.1---+ two.mysite.se | | two.worksite.se 192.168.1.3--+ +--192.168.2.3
要するに、二つのネットワークが、保護されていないネットワーク上を、IPSecトンネル経由で接続される、ということ。ここでプライベートインターネット用に予約されたIPアドレス (RFC1918) を使っていることは無視してほしい。なにかしら例は必要だったもんで。isakmpd を NAT と組み合わせて使うとかその手のをどうするかは説明しない(ぼく自身やったことがないから)。
では設定ファイルを見てやろう。以下は、セキュリティゲートウェイ gw.mysite.se用のファイルだ:
# ***************************************************************** # ************* gw.mysite.se isakmpd.conf のはじまり ************ # ***************************************************************** # A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. [General] Policy-File= /etc/isakmpd/policy Retransmits= 5 Exchange-max-time= 120 Listen-on= 10.0.0.1 # The name work-gw here is used just as a section name and a tag for # use in this configuration file below and need not actually be the # real hostname or domain name of the peer (but it could be). The IP # address however needs to be correct. Phase 1, as you might already # know, is to negotiate an ISAKMP security association (SA). There # should of course be one IP and name for each peer we want to # communicate with. [Phase 1] 10.0.0.2= work-gw # Now phase 2 is negotiating IPSec SAs. As in phase 1, the name here # is a section name to be used later. Actually, it can be a comma # separated list of section names here. Thus if traffic from many # networks (or individual hosts) should be forwarded through this # tunnel, more sectionnames would be added (and of course corresponding # new sections further down). [Phase 2] Connections= work-gw-my-gw # Now, here are some parameters for the ISAKMP SA negotiations. Almost # self documenting. The section name is from [Phase 1] above. The most # interesting tag might be the ID tag. The ID tag is set to the name # of the section where the identity information about this host that # will be presented to connecting peers, can be found. If the ID tag # is not available, isakmpd will assume that it will identify itself # using the IP address. You might also notice that there is no longer # any authentication tag here in this configuration. The authentication # data is currently used only in the preshared key case. [work-gw] Phase= 1 Transport= udp Local-address= 10.0.0.1 # Local address Address= 10.0.0.2 # Peer address ID= my-ID Configuration= Default-main-mode # This is the identity data. ID-type may also be IPV4_ADDR (the # default), IPV4_ADDR_SUBNET or UFQDN. The Name tag is used for # FQDN and UFQDN, for IPV4_ADDR an Address tag would be used instead. # For IPV4_ADDR_SUBNET a Network and a Netmask tag would be used. [my-ID] ID-type= FQDN Name= gw.mysite.se # This is the section for the IPSec connection. The section name is # from the list in the [Phase 2] section above. The ISAKMP-peer is, # of course, the tag of our peer from section [Phase 1] above. The # Local-ID and Remote-ID tags should be section names describing which # packages should be forwarded over the IPSec tunnel to the remote # network. [work-gw-my-gw] Phase= 2 ISAKMP-peer= work-gw Configuration= Default-quick-mode Local-ID= Net-west Remote-ID= Net-east # ここで記述されたネットワーク上のコンピュータから発せられた # パケットで... [Net-west] ID-type= IPV4_ADDR_SUBNET Network= 192.168.1.0 Netmask= 255.255.255.0 # ... 以下の記述とマッチする目的地を持ったものは、暗号化されて # IPSecトンネル経由でリモートシステムに転送される。 [Net-east] ID-type= IPV4_ADDR_SUBNET Network= 192.168.2.0 Netmask= 255.255.255.0 # Main mode の記述 # Here are the data for main mode. Using DES here for real purposes # is not very smart since DES is no longer considered a secure # encryption algorithm. 3DES is generally considered to have much better # security since it has enough bits in the key to be considered secure. # Transforms is a list of tags describing main mode transforms. In # this example we have only one. [Default-main-mode] DOI= IPSEC EXCHANGE_TYPE= ID_PROT Transforms= 3DES-MD5 # Certificates stored in PEM format # This is important when using certificates. The CA certificates should # be in the CA-directory (but not the CA private key ofcourse). # The Cert-directory should have at least the certificate for the # local host but other certificates are also allowed. The private key # should be the private key of the local host. [X509-certificates] CA-directory= /etc/isakmpd/ca/ Cert-directory= /etc/isakmpd/certs/ Private-key= /etc/isakmpd/private/local.key # Main mode transforms ###################### # Here is our main mode transform. The important thing here is to use # RSA_SIG as authentication method when using certificates. It is the # only method supported when using certificates so far. Commercial # entities in the US will thus have to wait until September 2000 to # use this due to the RSA patent. Luckily, I am not living in the US. # Also important is the GROUP_DESCRIPTION tag. It must match the # GROUP_DESCRIPTION tag in the Quick mode transforms further down. # The Life tag here could possibly be modified. The LIFE_60_SECS might # be shorter than necessary for normal use. [3DES-MD5] ENCRYPTION_ALGORITHM= 3DES_CBC HASH_ALGORITHM= MD5 AUTHENTICATION_METHOD= RSA_SIG GROUP_DESCRIPTION= MODP_1024 Life= LIFE_60_SECS,LIFE_1000_KB # Quick mode description ######################## [Default-quick-mode] DOI= IPSEC EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-3DES-MD5-PFS-SUITE # Quick mode protection suites ############################## # 3DES [QM-ESP-3DES-MD5-PFS-SUITE] Protocols= QM-ESP-3DES-MD5-PFS # 3DES [QM-ESP-3DES-MD5-PFS] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-3DES-MD5-PFS-XF # Quick mode transforms # Don't forget. The GROUP_DESCRIPTION must match the GROUP_DESCRIPTION # in main mode above. For forwarding packets between two networks (or # from a host to a network) we use TUNNEL mode. Between two hosts we # may also use TRANSPORT mode instead. [QM-ESP-3DES-MD5-PFS-XF] TRANSFORM_ID= 3DES ENCAPSULATION_MODE= TUNNEL AUTHENTICATION_ALGORITHM= HMAC_MD5 GROUP_DESCRIPTION= MODP_1024 Life= LIFE_60_SECS # As we know from the isakmpd.config manpage the LIFE_DURATION here is # an offer value (60), a minimum acceptable value (45) and a maximum # acceptable value. The isakmpd.conf example has this set to # 600,450/720 instead. That might be a better value for normal use. [LIFE_60_SECS] LIFE_TYPE= SECONDS LIFE_DURATION= 60,45:72 [LIFE_1000_KB] LIFE_TYPE= KILOBYTES LIFE_DURATION= 1000,768:1536 # ***************************************************************** # ************* End of the gw.mysite.se isakmpd.conf ************** # *****************************************************************
ここまではローカルシステム用の設定。リモートシステムの設定もまったく同じだけれど、裏返しになる。だからちがうのはisakmpd.conf ファイルの頭のところだけだ。セキュリティゲートウェイgw.worksite.seの isakmpd.conf ファイルの頭のところだけ見てやろう:
# ***************************************************************** # ************** gw.worksite.se isakmpd.conf のはじまり *********** # ***************************************************************** [General] Policy-File= /etc/isakmpd/policy Retransmits= 5 Exchange-max-time= 120 Listen-on= 10.0.0.2 [Phase 1] 10.0.0.1= my-gw [Phase 2] Connections= work-gw-my-gw [my-gw] Phase= 1 Transport= udp Local-address= 10.0.0.2 # Local address Address= 10.0.0.1 # Peer address ID= work-ID Configuration= Default-main-mode [work-ID] ID-type= FQDN Name= gw.worksite.se [work-gw-my-gw] Phase= 2 ISAKMP-peer= my-gw Configuration= Default-quick-mode Local-ID= Net-east Remote-ID= Net-west # ***************************************************************** # ************************* ... つづく... ************************* # *****************************************************************
あまりむずかしくはなかったね。ただ読むのはちょっと退屈だったかもしれないけれど。次の部分は、もうちょっとおもしろくなる。
実をいえば、policy ファイルは初めての人にはちょっとややこしいかもしれない。特に思い通りに動かないときには。man-ページ isakmpd.policy(5) は、実はそんなに悪くない。ところどころはっきりしないところがあるけれど、全体としてはいい。
一番簡単な、ちゃんと機能する policy ファイルはたった一行だ:
authorizer: "POLICY"
これは要するに、だれが接続していいかについて、ポリシー上の制約はなにもない、ということだ。だからあまりセキュリティの高い設定ではない。ここの authorizer タグは、policy を決める権限を持った人物、ということだ。特別 authorizer である"POLICY" は、policy について最終的かつ無限の権限を持つ。それ以外の authorizer は、ここで権限を持つためにはまず "POLICY" に認定してもらわなければならない。
さらに何が許されるかについて、条件群があるかもしれない。以下の policy はだから、本物の暗号を何か使って ESPプロトコルを使用した人だけが認定されるということだ(本物といってもまあ、これだと DES を使っている人も認められて、DES はいまやほとんどインチキと思ってもいいくらいだけれど、でも DES を認めないようにこの policy を変更するのは、読者の練習問題として残しておこうか)。これだとESP で暗号化する人ならだれでも認められることに注意。
authorizer: "POLICY" conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" -> "true";
さらに権限をだれか他の存在(複数でもいい)に「サブライセンス」することもできる。簡単なケースとしては、事前共有鍵の場合だ。この場合、事前に共有されたパスワードを知っている人はすべて認められる。だから:
authorizer: "POLICY" licensees: "passphrase:something really secret" conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" -> "true";
これはこのパスワードを知って条件にマッチした人すべてに接続を認める(ただしこのパスワードは isalmpd.conf の Authentication タグでも設定しておくのをお忘れなく)。
ここまでは何もむずかしくない。こっからがおもしろいところ。まず、ライセンスを受ける存在はたくさんあってもいいけれど、そのすべてが "POLICY"に認定されなくてはならない。さらに認定されたライセンス保持者は、他のライセンス保持者にサブライセンスを出せる。ライセンス保持者は、policyファイルでさらに記述されていたら単なるストリングでもいい:
authorizer: "POLICY" licensees: "subpolicyAH" || "subpolicyESP" conditions: app_domain == "IPsec policy" -> "true"; authorizer: "subpolicyESP" licensees: "passphrase:something more secret" conditions: esp_present == "yes" -> "true"; authorizer: "subpolicyAH" licensees: "passphrase:something really secret" conditions: ah_present == "yes" -> "true";
さあみなさんお待ちかねの部分。Policy はまた、鍵にサブライセンスしたり権限委譲したりできる。この場合の鍵は、ふつうはX.509 証明書だ。証明書を簡単に使うには、それをパスワードがわりに使うことだ。policy ファイルに個別ユーザの証明書を加えるだけでいい:
keynote-version: 2 comment: This is an example of a policy delegating to a key. authorizer: "POLICY" licensees: "x509-base64:\ MIIBsTCCARoCAQAwDQYJKoZIhvcNAQEEBQAwITELMAkGA1UEBhMCc2UxEjAQBgNV\ BAMTCUlLRUxBQiBDQTAeFw0wMDAxMjgxNzQyMTZaFw0wMTAxMjcxNzQyMTZaMCEx\ CzA この部分はユーザ証明書でございますな AQEB\ BQA IUuz\ eOW8P5UGJUH2JVkiA2CTDryFf0CHYwd2P003dtVYw5RvET7XLMpRZiCcWtBdxneW\ ct+016zUBP/cQMMl+KownxAUq9ezA8GvTyUWC97SOMOgoVj/QR3FHmEjpUi3AgMB\ AAEwDQYJKoZIhvcNAQEEBQADgYEALGShaAxHvGncev0iFnKrJI4x5T4vlaMP1ad+\ iWLV5q9H3wickVGN0NPerq0YLwx/VA9WaecYN8V+ALtNKYPuDiT11zwvE8GQeaai\ NuzgmQ9hh3GifEgN9VEiC3j4kTytonKr0Q+vTLM7xYzheOxvrtUErRwZ9Xs1KzHe\ yiXHSU8=" conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" -> "true";
さて、ユーザの数が多ければ、このやり方がばかげているのはすぐわかる。isakmpd が CA- ディレクトリと Certificate ディレクトリから読んでくる証明書と、ピアから送られてくる証明書は、疑似資格証明(credentials)に変換される。こうした疑似資格証明に変換された証明書は、こんな感じになっている:
authorizer: "x509-base64:\ MIIBsTCCARoCAQAwDQYJKoZIhvcNAQEEBQAwITELMAkGA1UEBhMCc2UxEjAQBgI2\ CzA この部分はユーザ証明書(つまりCA証明書)に署名した AQEB\ BQA 人の公開鍵/証明書ですな IUuz\ eOW8P5UGJUH2JVkiA2CTDryFf0CHYwd2P003dtVYw5RvET7XLMpRZiCcWtBdxneW\ ct+016zUBP/cQMMl+KownxAUq9ezA8GvTyUWC97SOMOgoVj/QR3FHmEjpUi3AgMB\ AAEwDQYJKoZIhvcNAQEEBQADgYEALGShaAxHvGncev0iFnKrJI4x5T4vlaMP1ad+\ iWLV5q9H3wickVGN0NPerq0YLwx/VA9WaecYN8V+ALtNKYPuDiT11zwvE8GQeaai\ NuzgmQ9hh3GifEgN9VEiC3j4kTytonKr0Q+vTLM7xYzheOxvrtUErRwZ9Xs1KzHe\ yiXHSU8=" licensees: "x509-base64:\ MIIBsTCCARoCAQAwDQYJKoZIhvcNAQEEBQAwITELMAkGA1UEBhMCc2UxEjAQBgNV\ BAMTCUlLRUxBQiBDQTAeFw0wMDAxMjgxNzQyMTZaFw0wMTAxMjcxNzQyMTZaMCEx\ CzA ここんとこは証明書を受ける側の鍵に AQEB\ BQA なります IUuz\ eOW8P5UGJUH2JVkiA2CTDryFf0CHYwd2P003dtVYw5RvET7XLMpRZiCcWtBdxneW\ ct+016zUBP/cQMMl+KownxAUq9ezA8GvTyUWC97SOMOgoVj/QR3FHmEjpUi3AgMB\ AAEwDQYJKoZIhvcNAQEEBQADgYEALGShaAxHvGncev0iFnKrJI4x5T4vlaMP1ad+\ iWLV5q9H3wickVGN0NPerq0YLwx/VA9WaecYN8V+ALtNKYPuDiT11zwvE8GQeaai\ NuzgmQ9hh3GifEgN9VEiC3j4kTytonKr0Q+vTLM7xYzheOxvrtUErRwZ9Xs1KzHe\ yiXHSU8=" conditions: app_domain == "IPsec policy" -> "true";
さて、これらが "POLICY" に認められたものではないので、それをなんらかの形で認知する policy がなければダメだということに注意。さらに、これは内部で証明書がどうなっているかを説明している。上の資格証明(credential)は、policy ファイルの中では見られない。でも、そういう資格証明にサブライセンスは出せる。上のサブライセンス発行を思いだしてほしい。あれを使えば、CA証明書をライセンスとして "POLICY"に書いてやれば、ある CA が署名した証明書すべてにライセンスが出せる。
keynote-version: 2 comment: This is an example of a policy delegating to a key. authorizer: "POLICY" licensees: "x509-base64:\ MIIBsTCCARoCAQAwDQYJKoZIhvcNAQEEBQAwITELMAkGA1UEBhMCc2UxEjAQBgNV\ BAMTCUlLRUxBQiBDQTAeFw0wMDAxMjgxNzQyMTZaFw0wMTAxMjcxNzQyMTZaMCEx\ CzA この部分が CA 証明書でございますな AQEB\ BQA IUuz\ eOW8P5UGJUH2JVkiA2CTDryFf0CHYwd2P003dtVYw5RvET7XLMpRZiCcWtBdxneW\ ct+016zUBP/cQMMl+KownxAUq9ezA8GvTyUWC97SOMOgoVj/QR3FHmEjpUi3AgMB\ AAEwDQYJKoZIhvcNAQEEBQADgYEALGShaAxHvGncev0iFnKrJI4x5T4vlaMP1ad+\ iWLV5q9H3wickVGN0NPerq0YLwx/VA9WaecYN8V+ALtNKYPuDiT11zwvE8GQeaai\ NuzgmQ9hh3GifEgN9VEiC3j4kTytonKr0Q+vTLM7xYzheOxvrtUErRwZ9Xs1KzHe\ yiXHSU8=" conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" -> "true";
つまり上の policy は、CA に権限委譲する policy の簡単な例だ。この証明書を持った CA が署名した証明書を持っていて policy と設定ファイルの設定したほかの条件にもしたがっているユーザはすべて認められる。
さて、本当に安全を期するなら、これでは残念ながら十分ではないのだ。こういう設定のセキュリティゲートウェイを攻撃する方法がある。もし細々した話がいらないなら、いますぐ次の節まで飛ばそう。それ以外の人たちは、なぜこれが安全でないかを理解してみようではないの。むずかしくはないよ。
この段階で、isakmpds がどんな情報にアクセスできるか考えてほしい。設定ファイルから、isakmpd はピアがどの IP-アドレスから送信してくるかわかる([フェーズ 1] セクションで)。フェーズ 1 のネゴシエーションをするときに得られる情報から、ピアがどんな ID を出してくるかわかって、ピアからの証明書をもらったらそれでピアが本当にそのIDを持っていることが証明される。問題なさそうだね?
うん、もしID 情報が IP なら(フェーズ 1 の ID セクションを使わなければこれがデフォルトに状況になる)すべてはオッケーだ。CA はその IP を cert に結びつけて、設定の中の IP だけで必要情報はすべてそろう。なりすまし犯が、ほかのコンピュータから同じ IP を使うことも不可能ではない(たとえば両方のコンピュータが同じ LAN 上にあって、ふだんその IP を使っているマシンがなんらかの理由でダウンしているなど)。でも、なりすまし犯が、証明書とそれに対応する秘密鍵を持って、その IP がなりすまし犯のものだと(不正に)証明することは不可能なはずだ。
もしそれが万が一起こったら、そのなりすまし犯はそのIPの所有者から秘密鍵をどうにかして盗んだか、あるいは CA をなんらかの方法でだまして、にせの情報を含んだ証明書を発行させたかのどちらかだ。もしこのいずれかが起こったなら、秘密鍵の保護が不十分だったか、CA がなりすまし犯の身元(あるいは cert の ID 情報)を十分にチェックできなかったか、あるいは CA 秘密鍵が十分に保護されていなかったかだ。これらはすべて、そもそもセキュリティがまともに機能する前提なので、こういう状況は絶対に起こってはいけない。
さてぼくたちの例では状況がちがう。ここでは証明書の中に、IPアドレスではなく FQDN が入っている。[Phase 1] セクションにまだ IP アドレスがあるので、これはセキュリティ問題となる可能性がある。ISAKMP フェーズ 1 ネゴシエーションの間に何が起きるかというと、ピアが期待どおりの IP から送られてきたことをチェックできる(でもさっき説明したように、これは一部の状況ではごまかせる)。ピアが提示するIDを、本当にそのピアが持っていることもチェックできる。でも、いまチェックできないのは、そのID が本当にそのピアが持っていると期待すべき ID なのか、ということだ。isakmpd は、どんな ID を期待すればいいか一度も教わっていないからだ。
DNS システムがホストのために IP を FQDN と結びつけてくれる、という人もいるだろう。それはそうなんだけれど、現在の DNS システムはセキュリティが高くないし、だましてにせの情報を出させることも、場合によってはできる(あるいはサービス拒否(DoS)攻撃を攻撃者に受けて、その攻撃者のマシンがDNSサーバの答を偽造することもできる)。いずれ高セキュリティ DNS も登場するけれど、まだ出回っていないし(少なくともほとんどの DNS サーバはまだ高セキュリティではない)、だから現在、cert の FQDN が期待される IP と対応しているかを調べるのに DNS を使っても保証にはならない。実は isakmpd はこれを DNS にきいたりしない。DNS が安全でも、UFQDNを使っている場合にはこれをチェックできない。
つまり ID として FQDN を使う場合、アタッカーは自分の秘密鍵を用意して、それをわれわれの使うのと同じ CA に署名させる(でももちろんアタッカー自身の FQDN を使って)。それからピアに DoS 攻撃をしかけてダウンさせる (実は ISAKMP プロトコル自体に欠陥があって、ピアに対してリモートDoS を仕掛けてダウンさせてしまえる可能性があるけれど、isakmpd がこういう攻撃に対してどのくらい敏感かは知らない)。それからアタッカーは自分のコンピュータをわれわれのピアと同じように設定して、ピアのネットワークにつないで自分のIDと秘密鍵と証明書を使える。
ぼくたち側の isakmpd は、こっちのピアへの ID が何かを教わっていない(そしてそれは、アタッカーが証明書とIDと秘密鍵以外はまったく同じ設定にしておいたから)。さらにぼくたちの isakmpd は証明書が同じ CA のサインしたものだとチェックできる(でも多くの CA はcert をいっぱいサインするから、cert を手に入れるのはむずかしくないかも)。そしてそこで示された ID が証明書の中の ID といっしょなのも確認できる。でも、これまで提示された設定では、その ID が期待していた ID かどうかはチェックできない。だからアタッカーは接続を認められてしまう。
すると問題は、どうやったら isakmpd に期待すべき ID のことを教えてあげられるか、ということだ。ありがたいことにこれは簡単で、 isakmpd.policy(5)にも説明されている。policy内でチェックをかけなきゃいけないのだ。たとえばこんなふうに:
keynote-version: 2 comment: This is an example of a policy delegating to a key. authorizer: "POLICY" licensees: "x509-base64:\ MIIBsTCCARoCAQAwDQYJKoZIhvcNAQEEBQAwITELMAkGA1UEBhMCc2UxEjAQBgNV\ BAMTCUlLRUxBQiBDQTAeFw0wMDAxMjgxNzQyMTZaFw0wMTAxMjcxNzQyMTZaMCEx\ CzA この部分が CA 証明書でございますな AQEB\ BQA IUuz\ eOW8P5UGJUH2JVkiA2CTDryFf0CHYwd2P003dtVYw5RvET7XLMpRZiCcWtBdxneW\ ct+016zUBP/cQMMl+KownxAUq9ezA8GvTyUWC97SOMOgoVj/QR3FHmEjpUi3AgMB\ AAEwDQYJKoZIhvcNAQEEBQADgYEALGShaAxHvGncev0iFnKrJI4x5T4vlaMP1ad+\ iWLV5q9H3wickVGN0NPerq0YLwx/VA9WaecYN8V+ALtNKYPuDiT11zwvE8GQeaai\ NuzgmQ9hh3GifEgN9VEiC3j4kTytonKr0Q+vTLM7xYzheOxvrtUErRwZ9Xs1KzHe\ yiXHSU8=" conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" && remote_id == "gw.worksite.se" -> "true";
これで、IPSec接続を得られるのは gw.worksite.se だけのはず。ほかに remote_idのチェックを足せば、許可されるIDは簡単に増える。つまり以下のようなのを policy に足せばいい:
conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" && (remote_id == "gw.worksite.se" || remote_id == "gw.whatsite.se") -> "true";
この policy だと、gw.worksite.se, gw.somesite.se、gw.whatsite.se のいずれも接続できる。
policy に証明書丸ごと含めなくてはならないのは残念、という人もいるだろう。証明書を policy に入るような形式になおすのは手間だし、policy も読みにくくなる。だれかがまちがって、ややこしい policy のなかで、CA 証明書とまちがえてユーザ証明書を入れてしまったら、権限のないユーザも接続が認められてしまうかもしれず、さらに困ったことに、policy ファイルを見てもそれをつきとめるのはむずかしい (X.509 証明書は人間に読める形ではないから)。
さて、本当にカリカリの最先端の人たちには、この問題の解決方法がある。いまでは、policy 内で証明書そのもののかわりに、証明書のDistinguished Name (DN) を使うことができる(対応する証明書はもちろんディスク上の certs か ca ディレクトリにあって、isakmpd が見つけられるようになっていること)。この形式だと、上の policy は以下のような感じになるだろう:
keynote-version: 2 comment: This is an example of a policy delegating to a key. authorizer: "POLICY" licensees: "DN:\C=se\CN=IKELAB CA" conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" && (remote_id == "gw.worksite.se" || remote_id == "gw.somesite.se" || remote_id == "gw.whatsite.se") -> "true";
ずっと読みやすい、でしょ? ある証明書の正確な DN は、openssl ユーティリティを使って証明書を見てやるとわかる。こんな具合:
$ openssl x509 -text < ca.crt
もっと複雑な policy はもちろんできるけれど、これはとりあえず入門だし、次の節で別の例を見てやることになる。
これで ca.crt の中の証明書について必要な情報が提供されるはずだ。policy が小さいか、そこそこくらいならこれでもいいだろう。でも巨大なサイトで接続ユーザが山ほどいるなら、これでもまだまだだ。
それじゃ isakmpd のホントにクールな機能をいくつか見てやろう。これまでは、接続してくるはずのピアはよく知られていて、IPアドレスも静的に固定されているものとした。でも、そういう場合ばかりじゃない。動的に割り当てられたIPを使ったり、コンピュータを何台も使ったりする人は多い。あるいは(サーバなんかだと)接続したいのがだれなのか、はっきりわからないこともある。
そこでisakmpdのすてきな機能の一つは、[Phase 1]セクションでIPではなくデフォルトのタグを使えるというもの。これによって、isakmpdはどのIPからでもネゴシエーションを受け付けられるようになる。これはこんな感じになる:
[phase 1] Default= work-gw
まず言っておくべきなのは、この設定はDoS攻撃に対して安全ではないかもしれないということ。まえにも言ったように、ISAKMP/IKEプロトコルには欠陥がある。いずれにしても、デフォルトの [phase 1] セクションを使えば、一種の「認証証明書」が変わりに使えるようになる。
たとえば権限を持つユーザはたくさんいるけれど、でも誰でもいいからうけつける、というわけではない場合を考えてみよう。たとえば会社なんかの場合。会社の従業員は接続させたいけれど、それ以外の人には接続してほしくない。さて、大企業で社員が何千人もいるとしよう。かれらがどのコンピュータからでも(社内LAN上のものに限らず)接続できるようにしたいけれど、全員がなんでもできるようにはしたくない。この場合、次のようなpolicy が書けるはずだ:
keynote-version: 2 authorizer: "POLICY" licensees: "telnet@work" || "telnet@lab" || "pop3@work" conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" && remote_id_type == "UFQDN" && (remote_id == "telnet@worksite.se" || remote_id == "pop3@worksite.se" || remote_id == "telnet@lab.worksite.se") -> "true"; authorizer: "telnet@work" licensees: "DN:\C=se\CN=IKELAB CA" conditions: remote_id == "telnet@worksite.se" && local_filter_type == "IPv4 address" && local_filter_port == "23" && local_filter == "192.168.002.003" authorizer: "telnet@lab" licensees: "DN:\C=se\CN=IKELAB CA" conditions: remote_id == "telnet@lab.worksite.se" && local_filter_type == "IPv4 address" && local_filter_port == "23" && local_filter == "192.168.002.002" -> "true"; authorizer: "pop3@work" licensees: "DN:\C=se\CN=IKELAB CA" conditions: local_filter_type == "IPv4 address" && local_filter_port == "110" && local_filter == "192.168.002.003" && remote_id == "telnet@worksite.se" -> "true";
これは厳密に正しいかどうかはわからん。ぼくが知る限り、こいつはまったくテストしていない(だからこのフィルタ条件は、ぼくの思い通りにはぜんぜん動かないかもしれない)。それと、こいつみたいなpolicy (というか、デフォルトがピアのIPにしてあるものすべて)は、isakmpd.confファイルもあわせて書き換えないとダメだ。これには、セキュリティ上の問題もついてまわる。さらに、だれでも接続できるようになっているこの種の接続では、たぶん接続した人の DN はすべてログしておいたほうが望ましい。isakmpd はぼくの知る限りでは、これをまだサポートしていない。さらにこの可能性にはべつのセキュリティ上の問題がついてくるかもしれない。なにかあっても、だれも責任はとってくれないので、覚悟して進むように。でも基本的な考え方はもうはっきりしているはずだ。
いまのが持っている、実におもしろい可能性に思い当たらない人がいるとアレだから、念のため説明しておこう、もしこういう形でISAKMP/IKE を使っているコンピュータがすべて、リモートからユーザが使いたいと思っているサービスのそれぞれについて、条件の束を持っていたとしよう。すると CA は、ユーザの証明書にしかるべき SubjectAltName extension を入れておくだけでそのユーザの認証ができる。さらに、そういう証明書の有効期限を比較的短いものにしておいて、ユーザは証明書が古くなってきたら証明書を再発行してダウンロードできるようにしておく。もしユーザが権限を悪用するなら、証明書を再発行しないようにすれば、有効期限後は入ってこられない。社員が一人やめたくらいで、すべてのコンピュータ上のpolicyファイルを変える必要もない。同じ方式はISAKMP/IPsec 以外の目的にも使えるはずだ(オフラインシステムの認証さえできる!)。ただしその場合には特別なソフトが必要になるけれど。とにかく。これをやる組織はおそらく自分で自分自身のCAになったほうがいい。
こういうマルチユーザ設定(モバイルユーザ)は、事前共有鍵でもできうけれど、でもそれだと、どのIPから接続してくるかわからないから、IDをもとに正しいパスワードが選べるようになっている必要がある。だからID_PROTモードではなくAGGRESSIVE モードを使わなくてはならない(AGGRESSIVE モードでは、IDはネゴシエーションの初期の段階で送られるけれど、暗号化されないで送られる。だからAGGRESSIVE モードのほうがメッセージ交換が少なくてすむので、高速だけれど、IDがナマのままで送られるからちょっとセキュリティは下がる)。
isakmpd は、OpenBSD についてくる ISAKMP/Oakley 鍵管理デーモンだ。たぶん、ほとんどの ISAKMP 実装とは、部分的にせよ相互運用可能だと思うけれど、実際にテストされたのは以下のものだ。出回っている isakmp ソフトの一部は、実は OpenBSD isakmp デーモンをベースにしたものだったりする。
以下の MS-Windows クライアントは、互換性があるとの報告がある:
以下のゲートウェイ/ルータも互換性があるとの報告:
IPSec トラブルシューティングの最初のツールはtcpdump(8)だ。tcpdump を使っていくつか探すべきものを挙げると:
まずOpenBSDの tcpdump を使っている人は、拡張版の tcpdump を使っているので、ESP と AH パケットについても情報がとれる。もし OpenBSD2.5 や他の OS の tcpdump を使っているなら、たぶん古いバージョンだから AH や ESPについてはプロトコル番号しか表示されない(ESP は IP プロトコル 50, AH は 51)。
たとえば、208.1.1.1 と 208.2.2.2 の2つのホストがある。208.2.2.2 にログオンして、以下をやってみよう:
vpn# ping -c 3 208.1.1.1 PING esp.mil (208.1.1.1): 56 data bytes 64 bytes from 208.1.1.1: icmp_seq=0 ttl=255 time=190.155 ms 64 bytes from 208.1.1.1: icmp_seq=1 ttl=255 time=201.040 ms 64 bytes from 208.1.1.1: icmp_seq=2 ttl=255 time=165.481 ms --- esp.mil ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 165.481/185.558/201.040 ms別のセッションでは、encapsulated されたpingが見られる:
vpn# tcpdump -ni fxp7 host 208.1.1.1 tcpdump: listening on fxp7 14:12:19.630274 esp 208.2.2.2 > 208.1.1.1 spi 0x00001000 seq 4535 len 116 14:12:19.813519 esp 208.1.1.1 > 208.2.2.2 spi 0x00001001 seq 49313 len 116 14:12:20.630277 esp 208.2.2.2 > 208.1.1.1 spi 0x00001000 seq 4536 len 116 14:12:20.832458 esp 208.1.1.1 > 208.2.2.2 spi 0x00001001 seq 49314 len 116 14:12:21.630273 esp 208.2.2.2 > 208.1.1.1 spi 0x00001000 seq 4537 len 116 ^C 1831 packets received by filter 0 packets dropped by kernel
# Passing in ISAKMP traffic from the security gateways pass in on ne0 proto udp from gatewB/32 port = 500 to gatewA/32 port = 500 pass out on ne0 proto udp from gatewA/32 port = 500 to gatewB/32 port = 500 # Passing in encrypted traffic from security gateways pass in proto esp from gatewB/32 to gatewA/32 pass out proto esp from gatewA/32 to gatewB/32
# Passing in Photuris traffic from the security gateways pass in on ne0 proto udp from gatewB/32 port = 468 to gatewA/32 port = 468 pass out on ne0 proto udp from gatewA/32 port = 468 to gatewB/32 port = 468 # Passing in encrypted traffic from security gateways pass in proto ah from gatewB/32 to gatewA/32 pass out proto ah from gatewA/32 to gatewB/32
# /sbin/isakmpd -d -DA=99
あるいは(いちばん詳しいタイマーデバッグ情報をとばすには)
# /sbin/isakmpd -d -DA=99 -D1=70
# Passing in traffic from the designated subnets. pass in on enc0 from netB/netBmask to netA/netAmask
vpn% netstat -rn -f encap Routing tables Encap: Source Port Destination Port Proto SA(Address/SPI/Proto) 0.0.0.0/32 0 192.168.99/24 0 0 208.1.1.1/00001000/50 0.0.0.0/32 0 208.1.1.1/32 0 0 208.1.1.1/00001000/50 208.1.2.0/24 0 192.168.99/24 0 0 208.1.1.1/00001000/50 208.1.2.0/24 0 208.1.1.1/32 0 0 208.1.1.1/00001000/50 208.1.5.0/24 0 192.168.99/24 0 0 208.1.1.1/00001000/50 208.1.5.0/24 0 208.1.1.1/32 0 0 208.1.1.1/00001000/50 208.2.2.2/32 0 192.168.99/24 0 0 208.1.1.1/00001000/50 208.2.2.2/32 0 208.1.1.1/32 0 0 208.1.1.1/00001000/50
IPSec が特に詳しく説明してあるのは vpn(8) man ページだ。各種の設定テンプレートが/usr/share/ipsec/ディレクトリにあるので役にたつだろう。enc(4), ipsec(4), ipsecadm(8), photurisd(8), startkey(1), isakmpd(8), isakmpd.conf(5) and isakmpd.policy(5) のmanページも詳しくて、IPSecの設定と運用に役立つはずだ。
その他リンクとして……
[FAQ トップへ] [12.0 - 高度なユーザ向け] [14.0 - OpenBSD のハードディスク]
www@openbsd.org 翻訳上の問題はhiyori13@alum.mit.eduまで。またyomoyomo氏より、各種ミスについてご指摘を受けました。多謝。
$OpenBSD: faq13.html,v 1.35 2000/07/25 00:07:53 chris Exp $