[{"data":1,"prerenderedAt":72},["ShallowReactive",2],{"article-j7zvrsp48lb":3,"prev-article-j7zvrsp48lb":27,"next-article-j7zvrsp48lb":51,"$fnnU7-asWXeC5NvFkA3JDxY4l_8MastKTy2ehWOkUX8U":64},{"contents":4,"totalCount":25,"offset":26,"limit":25},[5],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":8,"revisedAt":8,"title":9,"content":10,"tags":11,"is_no_index":24},"j7zvrsp48lb","2026-05-04T22:43:43.362Z","2026-05-05T00:07:59.619Z","Tailscaleやめたい","\u003Ch1 id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp>Tailscaleはネットワークの知識がない人が使うものだと思っていて、内心ずっと冷笑しているのですが、悪い噂をあまり聞かないので本当に悲しいです。用途に応じて使い分けろという話なんだろうとは思います。思いますが、他人の環境にアクセスしたいときに「まずTailscaleを入れて〜」みたいなことを言われると本当に嫌な気持ちになります。\u003C/p>\u003Cp>\u003Cs>ちなみに私も使っているので、あまり人のことを言えた義理ではありません。\u003C/s>\u003C/p>\u003Cp>便利なのは認めます。\u003Ccode>tailscale up\u003C/code>一発で直接インターネットへの疎通性を持たないホストに外から入れるのは素直に便利ですし、ちょっとしたマネジメント用途にはすごく使えるものだと思います。ただ、この便利は、OSのリゾルバ, netfilter, routing table他諸々に対する全力の侵襲と引き換えに成立しています。問題は、その侵襲の質が悪いことで、本当にストレスが溜まります。\u003C/p>\u003Cp>本エントリでは、これまでTailscaleを使ってきた中で頭にきたことを書いていきます。既に修正されたものもありますし、自分の設定が悪いだけのものも混ざっているかもしれません。それでも踏んだ事実は事実なので、忘れないうちに文句を言っておくことにします。\u003C/p>\u003Ch1 id=\"h89f5d63c3c\">resolv.confの扱い\u003C/h1>\u003Cp>tailscaledは起動するたびに\u003Ccode>/etc/resolv.conf\u003C/code>を書き換え、MagicDNS(100.100.100.100)をnameserverの先頭に挿入します。これがsystemd-resolvedとの相性が破滅的に悪い。\u003C/p>\u003Cp>systemd-resolvedはfollower modeで起動すると\u003Ccode>/run/systemd/resolve/resolv.conf\u003C/code>を生成します。tailscaledが事前に挿した100.100.100.100がここに混ざり、それを起動時の状態として読み戻し、upstreamのDNSの一つだと誤認して自身へ向けてDNSクエリを延々と転送し始めます。結果、内部キューが埋まってDNSが無事に死にます。\u003C/p>\u003Cp>これはGitHub上にもAmazon Linux環境での事象が報告されていて、報告者がtailscaleの中の人。タイトルが｢DNS stops working, and everything is very sad｣。very sadなのはこっちなんですけどね。あなたは知っててなぜ直さないんです？？？\u003C/p>\u003Cp>検出ロジックも杜撰で、systemd-resolvedかどうかを \u003Ccode>resolv.conf\u003C/code>のシンボリックリンク先のファイル名だけで判定しています。\u003Ccode>/etc/resolv.conf\u003C/code>が\u003Ccode>stub-resolv.conf\u003C/code>ではなくlegacy側にリンクされている場合、systemd-resolvedの存在に気づかず、direct モードに落ちてしまいます。諸々の組み合わせ全部を正しくハンドルしようとして、当然のように全部カバーできていません。これについて、tailscale公式ブログが“The Sisyphean Task Of DNS Client Config on Linux”と銘打って解説していますが、タイトルで自虐している時点で察してほしいです。\u003C/p>\u003Ch1 id=\"h77d9c93ff7\">RFC違反のDNS実装\u003C/h1>\u003Cp>resolv.confの話については、LinuxのDNS事情が混沌としてるのである程度同情の余地があります。しかし、tailscaleのDNSプロキシ実装そのものがRFCに準拠できていないのはどうにもなりません。\u003C/p>\u003Cp>EDNSのOPTレコードを完全無視します。クライアントがUDPのbuffer sizeを512 byteと広告していても、690 byte返してきます。RFC 6891がresponder MUST NOT exceed the requestor&apos;s buffer sizeと書いているものを、堂々とMUST NOT違反します。Cloudflareの子はちゃんとTC bitセットしてTCPフォールバックを促すのに、tailscale DNSはそれすらしません。\u003C/p>\u003Cp>DNS Flag Day 2020違反もあって、1232 byteを超えてもtruncateせずIPフラグメンテーションを起こします。上流からTC bit付きで返ってきても自分自身がTCPフォールバックできません。\u003C/p>\u003Cp>おまけに、EDNS Client Subnetを勝手にstripして米国IPに置換する挙動もあります。日本から繋いでるのにCDNが米国エッジに飛ばしてきます。MagicDNSを通すだけでレイテンシが100ms乗ります。VPN通すと遅くなるVPN、本当になんなんですか。\u003C/p>\u003Cp>極めつけがEDNS有無でキャッシュキーが分かれるsplit-brain cacheです。digとnslookupで同じドメインに対して別々の結果が(永続的に)帰ってきます。うーん困った。\u003C/p>\u003Cp>ちなみに文句はまだまだあって、tailscaledは \u003Ccode>resolv.conf\u003C/code>のsearch domainは保持するくせに、\u003Ccode>options ndots:5\u003C/code>を完全に剥がす振る舞いをします。Kubernetes環境なんかだとこれが致命的で、Pod内\u003Ccode>ping kuard.default\u003C/code>がbad addressで死んだ記憶があります。\u003C/p>\u003Ch1 id=\"h6d76dc14aa\">100.64/10をハードコードで全部drop\u003C/h1>\u003Cp>これが一番頭に来てる話です。\u003C/p>\u003Cp>ご存知の通り、tailscaleはtailnetのレンジとして100.64.0.0/10を使っています。曰く、「ISP用に予約された帯だから他のネットワークとぶつからない」らしい。確かにRFC 6598の定める100.64/10はService Provider向けのShared Address Spaceで、RFC 1918のものとは区別されています。とはいえ、インターフェース間のNATを介する用途であれば使用可能と明記されており、実際そう使っている方も多いのではないでしょうか。\u003C/p>\u003Cp>10/8と172.16/12がVPNやKubernetes Pod CIDRやDocker bridgeで埋め尽くされてる現状、まともにアドレス計画を立てたネットワークが100.64/10に逃げるのは普通の選択です。うちもそうしてます。自宅も会社もそう。ISPだけが使えるという前提がそもそも成り立っていません。\u003C/p>\u003Cp>それで、tailscaleを起動するとts-inputチェーンに\u003Ccode>DROP all -- !tailscale0 * 100.64.0.0/10 0.0.0.0/0\u003C/code>が挿入されます。tailscale0以外から来た100.64/10宛のパケットを全部drop。こちらが普通に内部で使ってる100.64/10宛の通信をtailscaleが勝手に殺してきます。困りますね。\u003C/p>\u003Cp>しかもこのDROPルール、tailnet policyで自分の使う範囲を100.65.64.0/22のように狭く指定しても、生成されるルールは依然として100.64.0.0/10全域です。コードを見ると\u003Ccode>util/linuxfw/nftables_runner.go\u003C/code>の\u003Ccode>addDropCGNATRangeRule\u003C/code>と\u003Ccode>createDropOutgoingPacketFromCGNATRangeRuleWithTunname\u003C/code>がそれぞれ別の方法で同じ範囲をルール化していて、片方は文字列正規化、もう片方は生の\u003Ccode>netip.Prefix\u003C/code>を利用しているようで。実装が二箇所に分散してる時点で察してほしいです。\u003C/p>\u003Cp>ちなみに、｢100.100.0.0/20で社内SSH運用してたサーバにtailscaleをインストールしたら、無条件で100.64/10全域DROPルールが入ってSSHを含むLAN通信が全切断、リモートからアクセス不能｣という事例がissueに上がっています。\u003C/p>\u003Cp>\u003Ca href=\"https://github.com/tailscale/tailscale/issues/12829\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/tailscale/tailscale/issues/12829\u003C/a>\u003C/p>\u003Cp>これ、2024年7月起票で現在もneeds-triageラベルのままopenです。triageもされてない。1年半以上。\u003C/p>\u003Cp>この回避策が\u003Ccode>--netfilter-mode=off\u003C/code>ですが、これはtailscale自身が公式ドキュメントでセキュリティリスクだと書いているフラグで、もうどうしようもないんじゃないの感があります。苦しい。\u003C/p>\u003Ch1 id=\"h729e032ab6\">iptablesの介入がすごく頭悪い\u003C/h1>\u003Cp>\u003Ca href=\"https://github.com/tailscale/tailscale/issues/320\" target=\"_blank\" rel=\"noopener noreferrer\">tailscaleの中の人が起票したissue\u003C/a>の本文がすごいです。\u003C/p>\u003Cblockquote>\u003Cp>The way we add iptables forwarding rules on Linux was an old hack that works for approximately nobody, except by coincidence. Refers specifically to an interface named ‘eth0’ which is very uncommon. Get re-added (but never deleted) every time the app starts. Creates a wildcard MASQUERADE rule rather than tight settings.\u003C/p>\u003C/blockquote>\u003Cp>これが、tailscale製品のLinuxサポートの土台です。中の人がそう書いています。\u003C/p>\u003Cp>それから、tailscaledは起動時にINPUT/FORWARDの先頭に\u003Ccode>ts-input\u003C/code>, \u003Ccode>ts-forward\u003C/code>を挿入し、POSTROUTINGのNATにts-postroutingを挿入します。これも普通の挙動っぽいですが、周期的に再配置して常に先頭にいるよう書き換えてくるのが本当にお行儀が悪い。iptables-restoreでルール順を組んでも、firewalldで管理しても、ufwで管理しても、tailscaleが定期的に後ろから殴って先頭に出てきてしまいます。\u003Ccode>--netfilter-mode=nodivert\u003C/code>を明示しようと周期再配置は止まりません。ユーザはホストのFWを管理してる気になっていますが、実際の支配権はtailscaleにあります。\u003C/p>\u003Cp>おまけにfwmarkも雑で、Calicoの上位16bitの使用とtailscaleの\u003Ccode>0x40000\u003C/code>, \u003Ccode>0x80000\u003C/code>が衝突し、CalicoのeBPFモードで\u003Ccode>Drop malformed IP packets Final result=DENY\u003C/code>が大量発生します。\u003C/p>\u003Ch1 id=\"hce2d3190fc\">MTU 1280ハードコード\u003C/h1>\u003Cp>\u003Ccode>tailscale0\u003C/code>のMTUは1280でハードコードされています。GCPの1460も、AWSの1500も、ジャンボフレームの9000も、全部関係なく1280です。\u003C/p>\u003Cp>WireGuardはICMP Frag Neededを信用しない実装で (DoS耐性のためらしい？)、まともなPath MTU Discoveryがありません。\u003Ccode>tailscale0\u003C/code>をさらにVXLANやWireGuardで重ねると実効MTUがさらに下がります。CiliumのVXLAN MTU 1280 + WireGuard 60 + tailscale 60で実効MTU ~1140になり、1252 byteのTLS Server Helloがちょうど切れる位置に来てdropされます。原因がMTUだと気付くのに半日。おかげさまで貴重な時間を無駄に過ごすことができました。\u003C/p>\u003Cp>私が知る限り、MTUを変える手段は存在しません。VPN製品でユーザにTCP MSS clampを要求するの、設計としてどうかと思います。\u003C/p>\u003Ch1 id=\"he6e50cfa9d\">ACLでDenyを明示できない\u003C/h1>\u003Cp>tailscaleのACLはdefault-denyを謳いながら、actionはacceptしか書けず、個別ルールでdenyを表現できません。\u003C/p>\u003Cp>一般的なFWアプライアンスであれば、\u003C/p>\u003Cpre>\u003Ccode>allow ssh from trusted_hosts\ndeny ssh\nallow * from any\u003C/code>\u003C/pre>\u003Cp>で「SSHは信頼できるホストからだけ、それ以外のSSHは拒否、他のポートは全公開」のようなものが書けます。しかし、tailscale ACLではこれが書けません。これは、最後の\u003Ccode>allow *\u003C/code>がSSH制限を上書きしてしまうためです。\u003C/p>\u003Cp>「\u003Ccode>tag:A\u003C/code>を\u003Ccode>tag:B\u003C/code>以外からブロック」を表現したいだけで、新タグを追加するたびにsrcリストを全書き換えする必要がでてきてしまい、かなりつらい。\u003C/p>\u003Cp>しかも\u003Ccode>acls\u003C/code>フィールドを省略するとdefault allow all。default-denyを謳いながら、書き忘れたtailnetは実質全許可。default-denyって言葉はどこに行ったんでしょうか？\u003C/p>\u003Cp>capability-basedの設計判断として一貫してるのは分かります。ただ、ACLを名乗りながら一般的なFWの動作と全く別物を提供するのはいただけない。\u003C/p>\u003Ch1 id=\"h507404909b\">SSOを強制\u003C/h1>\u003Cp>これは半分私の好みの話ですが。Tailscaleはアカウント作成にSSOを強制してきます。メールアドレスとパスワードでサインアップという選択肢がそもそも存在していません。\u003C/p>\u003Cp>個人で気軽に使う分にはGoogleで入れば済むので困らない〜みたいな主張をされがちですが、一段冷静に考えるとこれは結構な縛りです。tailnet全体のidentityが特定のIdPに紐付くということは、そのIdPアカウントが消えてしまった瞬間にtailnetから締め出されるということに他なりません。Googleアカウントが何らかの理由でロックされたら自分のホストにすら入られなくなる、というのを許容するかどうかは、判断する余地があって然るべきでしょう。しかしながら、Tailscaleはその判断を許してくれません。\u003C/p>\u003Cp>業務で使う場合だと話はさらに面倒で、「組織のGoogle Workspaceでサインアップしたが、退職時に組織のtailnetから個人を切り離したい」のような普通のユースケースがSSO強制のせいで歪な手順になります。tailnetを組織と個人で分けようとすると、別IdPを用意する必要があり、IdPの運用負担がVPNの運用負担に乗ってきます。VPNにIdPの寿命を縛られる、という構造そのものがおかしい。\u003C/p>\u003Cp>｢OIDC対応があるからセルフホストIdPでもいい｣という反論はあると思います。あると思いますが、家庭でVPNを立てたいだけの人間にKeycloakを建てさせるのは、もはやVPNの話ではありません。「VPNを使うために先にIdPを建てろ」という主張はそもそもの順序が逆です。\u003C/p>\u003Cp>そもそもTailscaleのcontrol planeはクローズドソースで、coordination serverに何を握られているかをユーザは検証できません。その上でidentityまでIdP経由で渡すことを強制される。便利の対価として、tailnetの存在条件をTailscale社とIdP事業者の二者に握られるのが現状です。Headscaleを建てれば回避できるのはそう。そうなんですが、それはTailscaleをやめることとほぼ同義でしょう。\u003C/p>\u003Ch1 id=\"h1afe451c43\">さいごに\u003C/h1>\u003Cp>それでも私はたぶん明日もTailscaleを使います。文句を言いながら使うのが一番楽だからです。wg-quickの設定ファイルを書いて鍵を配って繋がらないと喚いている時間より、Tailscaleに苦しめられる時間の方がまだ短いというだけの話であって、これをTailscaleが優れていると言っていいのかはまた別のお話です。\u003C/p>\u003Cp>Tailscaleが約束する“It just works”は、自分のネットワークのどこにTailscaleが侵入しているかを完全に把握した人にだけ成立する魔法のようなものです。そもそも完全に把握している人は態々Tailscaleを使う理由はないでしょう。Tailscaleの“It just works”は、Tailscaleを使う理由がなくなった人にだけ動作する素晴らしい設計です。よくできていますね。\u003C/p>\u003Cp>いい感じの代替を知っている方がいれば是非教えてほしいです。それでは。\u003C/p>\u003Cp>\u003C/p>",[12,18],{"id":13,"createdAt":14,"updatedAt":15,"publishedAt":14,"revisedAt":15,"slug":16,"name":17},"wia4slp55q","2025-04-28T07:14:14.541Z","2025-12-03T16:08:13.798Z","thoughts","独り言",{"id":19,"createdAt":20,"updatedAt":21,"publishedAt":20,"revisedAt":21,"slug":22,"name":23},"lte0t59xm8sb","2025-05-02T16:12:38.708Z","2025-12-03T16:06:52.753Z","network","ネットワーク",false,1,0,{"contents":28,"totalCount":50,"offset":26,"limit":25},[29],{"id":30,"createdAt":31,"updatedAt":32,"publishedAt":32,"revisedAt":32,"title":33,"content":34,"tags":35,"is_no_index":24,"summary":49},"0bs4f42te","2026-04-29T00:46:22.148Z","2026-04-29T01:01:31.544Z","向き不向きの前に、まず手を動かすべきでは","\u003Ch1 id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp>どうも、わたしです。\u003C/p>\u003Cp>最近、というかここ数年、タイムラインを眺めていると、「プログラミングを始めました！」「LLMでアプリを作りました！」みたいな投稿を頻繁に目にするようになりました。それ自体はとても素晴らしいことだと思いますし、新しく何かを始めようとしている人を否定するつもりは毛頭ありません。\u003C/p>\u003Cp>ただ、その後の様子を眺めていると、どうにも釈然としない気持ちになることが多くあります。\u003C/p>\u003Cp>｢動きません｣｢エラーが出ます｣｢分かりません｣｢何もしていないのに壊れました｣、そういう質問が、携わるコミュニティで、Twitterで、Discordで、GitHubで、毎日のように流れてきます。それ自体は別に良いんです。分からないことを聞くのも大事だと思いますから。\u003C/p>\u003Cp>問題は、その質問に何の情報も含まれていないことや、そもそも自分の手元で起きていることを、自分で確認すらしていないことです。\u003C/p>\u003Cp>タイトルは少しばかり煽情的かもしれませんが、自分自身も普段から書いては消し、書いては消しを繰り返している身として、向いてないと切り捨ててしまう前に、もう少し言いたいことがあります。そんな話を、つらつらと書き散らしていきたいなと。\u003C/p>\u003Ch1 id=\"h833a42ac8c\">エラーメッセージは目の前にあるのに何故か読まれません\u003C/h1>\u003Cp>世の中には、エラーが出た瞬間に、画面の前で固まる方々が一定数いらっしゃいます。\u003C/p>\u003Cp>固まったまま、5分、10分、酷い時には30分。エラーメッセージは画面の真ん中にずっと表示されているのですが、その本文を読んでいる気配がありません。読んでいたら、その後の口から｢分かりません｣という言葉が出てくるはずがないからです。\u003C/p>\u003Cp>\u003Ccode>Connection refused\u003C/code>, \u003Ccode>Permission denied\u003C/code>, \u003Ccode>Module not found\u003C/code>, \u003Ccode>Unexpected token\u003C/code>.\u003C/p>\u003Cp>これらは何かの呪文ではなく、コンピュータがあなたに対して、丁寧に問題を教えてくれている、とてもありがたい案内です。\u003C/p>\u003Cp>エラーメッセージを読むというのは、別に難しいことではありません。\u003Ccode>Connection refused 127.0.0.1:5432\u003C/code>と書いてあれば、｢ローカルの5432ポート宛接続が拒否された｣と読めばいいだけですし、5432はPostgreSQLのデフォルトポートなのでPostgreSQLが起動していないか、接続情報が間違っているか、そのあたりに当たりがつきます。1分もあれば原因に辿り着ける問題に何を無駄な時間を費やしているのでしょう。\u003C/p>\u003Cp>｢英語が読めません｣と言う方もいらっしゃいますが、refusedをリフューズドと読み下せれば、それだけで意味は推測できますし、どうしても分からなければ翻訳ツールに通せば済む話です。あなたが普段スマホで観ている海外動画の字幕、あれだって機械翻訳でしょ？同じです。\u003C/p>\u003Cp>そして、信じられないかもしれませんが、エラーメッセージを読まない方々は、何度プログラムを実行しても出続けるエラーに対して、毎回最初から驚きます。｢またこのエラーが出ました｣と言うのですが、そら当然です。書かれていることに対処しない限り、何回実行しても同じエラーが出ますし、コンピュータは、あなたの祈りとかには反応しません。中身を変えず同一の試行を繰り返した挙句、違う結果を望むのはとても愚かなことです。小学生ですらやりません。\u003C/p>\u003Cp>エラーが出るというのは本来ありがたいことです。間違っている箇所を教えてくれるものですから、感謝しながら読んで直せば済みます。逆に、エラーも出ずに動いている、けれど結果が間違っている、という状況の方が、遥かに恐ろしく感じます。エラーは敵ではありません。\u003C/p>\u003Ch1 id=\"h7437e44bed\">｢こう動くはずなんですけど｣って、それあなたの感想ですよね\u003C/h1>\u003Cp>これも本当によく見かけるパターンで、本当に心底嫌いです。\u003C/p>\u003Cp>曰く、｢私は、ここはこういう風に動くはずだと思ってるんですけど、動かないんですよ｣と。\u003C/p>\u003Cp>そうですか。それで、あなたの思いと実際の挙動、どちらが正しいと思います？\u003C/p>\u003Cp>答えは決まっています。動いていないのなら、あなたの思い10割10分が間違っています。\u003C/p>\u003Cp>ところが、自分の認識を譲らない方が一定数居るようで、｢いや、ここはこう動くはずなんですよ｣だとか、｢でも、こういう風に書いたんですから、こう動くはずじゃないですか｣みたいなことを平然と言ってのけます。すごい自信家ですよね、感心します。でも実は違うんです。あなたの認識と、コンピュータの実際の挙動がズレているんです。修正すべきは、コードでも、ライブラリでも、コンピュータでもなく、傲慢なあなた自身です。\u003C/p>\u003Cp>思いをベースに議論しても、コンピュータは1nmも動きませんし、コードを動かすのは、そこに書かれている事実です。実際に出力された値、実際に走った行、実際に発生したエラー等々。それらだけが、原因の手がかりであって、あなたの思いは、原因の特定に役立ちません。\u003C/p>\u003Cp>デバッグの第一歩は、自分の思いを一旦脇に置くことでしょう。｢ここは絶対こう動いているはず｣と思い込んでいる箇所こそ、\u003Ccode>print\u003C/code>でも \u003Ccode>console.log\u003C/code> でも \u003Ccode>dbg!\u003C/code> でも構わないので、実際の値を出力して確認してください。殆どの場合、あなたの思い込みは外れています。本当に、本当に、外れています。騙されたと思って私を信じてください。\u003C/p>\u003Cp>ちなみに、デバッガを使ったことがない方も、かなりいらっしゃるようですが、VSCodeでもJetBrains系IDEでもブラウザのDevToolsでも、ブレークポイントを置いて、ステップ実行して、変数の中身を覗く、ということができます。これを覚えるだけで、デバッグの効率が劇的に変わります。printデバッグも悪くはないのですが、ちゃんとしたデバッガを使えるようになっておくと、人生の何割かを取り戻せます。暇なら覚えておきましょう。\u003C/p>\u003Ch1 id=\"h471a83884c\">詰まったら考えるより先に手を動かそう\u003C/h1>\u003Cp>エラーメッセージを読みました。それでも原因が分かりません。さて、どうしましょうか。\u003C/p>\u003Cp>ここで多くの方が、画面の前で固まる作業に戻ります。けれど、それでは何も解決しません。考え込んでも、コンピュータは何も教えてくれません。\u003C/p>\u003Cp>ここでやるべき事は、手を動かして状況を観測することだけです。\u003C/p>\u003Cp>怪しい箇所の値を出力する。リクエストの中身をダンプする。条件分岐の手前で実行を止めて状態を覗く。データベースに直接クエリを投げて状態を確認する、みたいな。動いているはずと思っている部分が、本当に思った通りに動いているか、ひとつずつ確かめていく必要があります。\u003C/p>\u003Cp>考えてから手を動かすのではなく、手を動かしながら考えるべきです。これは、おそらくベテランの方も全く同じことをしています。違うのは、観測の精度と、観測する場所を絞り込む速度だけです。経験を積むと最初に怪しいと睨んだ箇所が当たる確率が上がっていく、というだけの話に思えます。\u003C/p>\u003Cp>さて、｢闇雲に試して動いたら、それで本当に直ったと言えるんですか？｣と言われてそうです。良い指摘です。実際、闇雲に値を変えていたら偶然動いた、というケースは、本質的な問題の解決には至っていません。\u003C/p>\u003Cp>しかし、観測した結果から｢ここの値が想定と違っていた｣と特定できれば、それは立派な原因究明です。観測のないトライアンドエラーは博打ですが、観測のあるそれは、ちゃんとしたデバッグであると考えます。\u003C/p>\u003Cp>考え込まないでください。手を動かしてください。コードは、あなたの思考の中ではなく、メモリ上で実際に動いています。\u003C/p>\u003Ch1 id=\"hd508ed06f1\">｢LLMに聞いたら違うことを言ってきました｣\u003C/h1>\u003Cp>そんな事を言うくらいなら、はなから私なんかに聞かずとも、永遠に一人寂しくLLMとイチャついてればいいと思うのですが、最近特に増えたのがこのパターンです。\u003C/p>\u003Cp>｢LLMに聞いたらこう書けばいいって言われたんですけど、動きません｣\u003C/p>\u003Cp>そうですか？うんうん、すごいでちゅね〜！それで、あなたはその実装を読みました？\u003C/p>\u003Cp>LLMが生成したコードは、それなりに動きます。それなりに、です。ライブラリに破壊的な変更があれば動きませんし、APIが廃止されていれば動きません。そもそもLLMの学習データに無かったマイナーなライブラリだと、平気でハルシネーションを起こします。実在しない関数を、自信満々で提案してきたりしやがります。\u003C/p>\u003Cp>それを確認もせずにコピペして、挙句、動かなかったら｢LLMが嘘をついたんだ！！！！｣と憤慨するのは、些か筋違いです。\u003C/p>\u003Cp>LLMは便利なツールですが、便利なツールを使うために必要な能力は、依然として人間側に求められています。これは、Stack Overflowが流行った時も、Qiitaが流行った時も、ChatGPTが流行った時も、Clineに全部賭けたときも、Cursorが流行った時も、ずっと変わっていません。\u003C/p>\u003Cp>LLMに頼ること自体は何も悪くありませんし、私も普段からLLMにかなりの出力を強要しています。GeminiにもOpusにも毎日お世話になっています。ただ、LLMが出力したコードは必ず自分で読みます。読んで理解して、おかしいところがあれば修正します。これをやらない人間がLLMを使うと、ただのコピペ職人が爆誕します。それも、自分が何をコピペしているかすら分からない、史上最悪のコピペ職人が、です。\u003C/p>\u003Cp>ちなみに、LLMに｢このコード動きません｣と投げて、LLMが返してきた修正をまたコピペして、それでも動かない、というループに陥っている方も散見されます。それを何時間も繰り返した挙句、LLMはダメだと結論付ける。残念ながら、ダメなのはLLMではなく、あなたの頭です。\u003C/p>\u003Cp>LLMはあなたの状況を完全には理解していません。あなたが理解した上で、適切に指示を出す必要があります。\u003C/p>\u003Cp>以前にも別の記事で書きましたが、LLMがどれだけ優秀になっても、使う人間の側に何もなければ、出力される成果物も同様のものでしょう。\u003C/p>\u003Ch1 id=\"h5cbe4915a0\">自分が何をしたいのか整理して\u003C/h1>\u003Cp>これも本当によく言われます。やめてくださいね。\u003C/p>\u003Cp>｢○○がしたいんですけど、どうすればいいです？｣\u003C/p>\u003Cp>その○○が、抽象的すぎてなんと言うかものすごくふわっとしている。\u003C/p>\u003Cp>｢Webサイトを作りたいんだけど〜｣\u003C/p>\u003Cp>どんなサイトを？静的サイトですか、動的サイトですか？認証認可は必要ですか？どんなコンテンツを載せたいですか？利用者は何人を想定していますか？運用のコスト感は？収益化したいですか、趣味ですか？\u003C/p>\u003Cp>これらはあなたが答えるべき質問です。わたしが答える質問ではありません。\u003C/p>\u003Cp>目的を整理するというのは、プログラミング以前のごく当たり前の力です。これができないと、コードを書く以前に何を書けばいいかすら定まりません。そんなんじゃお話になりません。\u003C/p>\u003Cp>これはエンジニアリングの問題ではなく、もっと手前の自分の思考を整理して言語化する国語の問題です。プログラミングは思考を厳密にコンピュータが理解できる形に翻訳する作業ですから、思考が曖昧なままではそもそもコードに翻訳することすらままならないことは自明でしょう。\u003C/p>\u003Cp>紙でもメモアプリでもLLMでも構わないので、自分が何をしたいのかを書き出してください。やりたいこと、やるべきではないこと、分かっていること、分からないこと等々。整理されていない要望をぶつけられても、こちらは何も答えようがありません。\u003C/p>\u003Cp>そして、もうひとつ。課題文を読めない方も本当に多いです。\u003C/p>\u003Cp>例えば、業務でちょっとしたツールを依頼する場面で、｢Slackに来たメッセージのうち、特定のキーワードを含むものをスプレッドシートに記録してください｣と伝えたとします。これは、｢Slackからメッセージを受け取る｣、｢キーワードでフィルタする｣、｢スプレッドシートに書き込む｣の3つの工程に分解できる、ごく単純な依頼です。\u003C/p>\u003Cp>ところが、これが分解できない方は、依頼文を一塊のまま受け取って、最初の一歩で固まります。｢何から手を付ければいいんでしょうか｣と相談されるのですが、お渡しした依頼文には既に手を付ける順番が書いてあります。一文として読むのではなく、要素ごとに区切って読んでください。それだけで、何をすればいいかが見えてきます。\u003C/p>\u003Cp>これはもうプログラミング以前の、国語の問題です。\u003C/p>\u003Cp>それすらできないようであれば、小学生のお勉強からやり直すことを推奨します。\u003C/p>\u003Ch1 id=\"h0d45d9ccaf\">大きい問題に挑む前に小さい問題に分割して\u003C/h1>\u003Cp>｢○○を作ってください｣という課題が出たとします。例えば、社内向けのちょっとしたダッシュボード、みたいな。\u003C/p>\u003Cp>ここで、できない方は、いきなり全部を一気に書こうとして、数時間悩んだ末に画面の前で固まる作業に戻ります。｢データ取得をどう書いて、それをどう加工して、どうUIに表示して、認証はどうして、エラー処理はどうして…｣と、全てを同時に考えようとして、結局1行も書けないのです。\u003C/p>\u003Cp>わたしならこう書きます。\u003C/p>\u003Cpre>\u003Ccode class=\"language-csharp\">var dashboard = new Dashboard();\nvar data = await dashboard.FetchDataAsync();\ndashboard.Render(data);\u003C/code>\u003C/pre>\u003Cp>3行、終わり。これでダッシュボードが完成です。\u003C/p>\u003Cp>「いや、それじゃ動かないじゃないですか」と思われるかもしれません。その通りです。動きません。\u003Ccode>Dashboard\u003C/code> とかいう存在しない抽象クラスを呼んでいるだけですから、当然です。\u003C/p>\u003Cp>しかし、これで全体像は捉えられます。あとは適当に\u003Ccode>Dashboard\u003C/code>クラスと\u003Ccode>FetchDataAsync\u003C/code>、\u003Ccode>Render\u003C/code>の中身をそれぞれ実装するだけです。中身もいきなり全部書こうとせず、同じように存在しないメソッドを呼んでおいて後から埋めていきます。これを繰り返していると、いつの間にか動くものが出来上がっています。\u003C/p>\u003Cp>トップダウン設計と呼ばれたりもしますが、名前はどうでも良くて、要するに、自分が一度に考えられる範囲まで、問題を細かく細分化するということです。難しい問題を、難しいまま扱える人は、ごく一部の天才だけであって、私を含む殆どの無能は、問題を1ファイルに1,000行で書ける程度の小ささに分解しないと解けません。\u003C/p>\u003Cp>勉強すれば難しい問題も解けるようになると期待されている方もいらっしゃるかもしれません。残念ながら、勉強しても難しい問題は難しいままです。賢くなるのではなく、問題を小さくする技術を身につけるべきです。これは才能の話ではなく、訓練の話なので、正直誰でも身につけられるかと思います。\u003C/p>\u003Ch1 id=\"h89f6c9455f\">動的型付け言語を選ぶ前に考え直しませんか\u003C/h1>\u003Cp>ここから少し、私の個人的な好みが強く入ります。先に断っておきますね。\u003C/p>\u003Cp>私は動的型付け言語が好きではありません。PythonもRubyもJavaScriptも、業務では書きますが、好きでは無いです。理由は単純で、書いた本人が何を扱っているか分からないコードを、後から他人が読んで分かるはずがないためです。\u003C/p>\u003Cp>巷では｢Pythonは書きやすい｣だとか、｢JavaScriptは手軽｣だとか、馬鹿の一つ覚えのように永遠と言われています。確かに、書き始めるまでのハードルは低いでしょう。しかし、それは短期的には楽であるというだけの話であって、長期的には負債が積み上がります。\u003C/p>\u003Cp>引数が何の型か書かれていない関数。返り値が状況によって変わる関数。エラー時に\u003Ccode>None\u003C/code>を返したり、空文字を返したり、例外を投げたりする一貫性のない設計。これらは、動的型付け言語特有の問題ではありませんが、動的型付けの環境では検出されないまま放置されやすい傾向にあります。\u003C/p>\u003Cp>そして、そういうコードを書いた本人は、3ヶ月後には何ひとつ覚えていません。私にも前科があります。\u003C/p>\u003Cp>これからプログラミングを始めるのであれば、最初から型のある言語を選んでください。GoでもRustでもKotlinでもSwiftでも、TypeScriptでも、好きなものを選べば良いと思います。動的型付け言語から始めて後から型に移行するのは苦痛でしょうし、最初から型に親しんだ方が遥かに早いかと思われます。\u003C/p>\u003Ch1 id=\"ha2c9bbc147\">質問とか\u003C/h1>\u003Cp>環境, やりたかったこと, やったこと, 起こったこと, 試したこと, 仮説\u003C/p>\u003Cp>このあたりが揃っていれば、回答する側は、スムーズに原因を絞り込めます。逆に、これらが何ひとつ揃っていない｢動きません｣だけの質問は、回答できません。回答できないというより、回答する前の調査だけで時間が溶けて、結果として誰も答えなくなります。私ならムカついて返信しないこともあるかもしれません。\u003C/p>\u003Cp>｢初心者なので〜｣と前置きする方もいますが、初心者かどうかは関係ありません。初心者であろうと、そうでなかろうと、項目を埋めることはできますし、初心者ほど丁寧に書くべきです。慣れている人なら省略して伝わることも、初心者の場合は丁寧に書かないと伝わらないためです。\u003C/p>\u003Cp>これは偏見ですが、質問が下手な人は概ね実装も汚いです。例外もあるかもしれませんが、私の観測範囲ではほぼ相関しているように思います。質問を組み立てることは、(本質的に)状況を分解して構造化する作業であって、それがプログラミングそのものであるためです。質問が組み立てられないということは、思考が組み立てられないということと同義で、思考が組み立てられなければ、コードも書けないでしょう。当たり前です。\u003C/p>\u003Ch1 id=\"h4eac98b528\">｢ググれ｣が冷たく聞こえるのなら申し訳ないですが\u003C/h1>\u003Cp>わたしは以前、ggrksは最大限の優しさだと書きました。今でも、その考えは変わっていません。\u003C/p>\u003Cp>技術的な質問に対して｢自分で調べてね〜｣と返すのは、決して冷たいわけではありません。\u003C/p>\u003Cp>\u003Cs>答えるのが面倒くさい訳ではないと言ってしまうと大嘘になるのですが、\u003C/s>｢あなたが自分で調べれば、もっと正確で網羅的な情報が手に入りますよ｣の意であり、｢私が中途半端に答えるよりも、検索した方が確実ですよ｣という意味であり、｢自身で調べる力を身につけた方がしあわせになれますよ｣という意味でもあります。\u003C/p>\u003Cp>これを冷たいと感じる方は、自分が答えを与えてもらえる立場だと思い上がっているのかもしれません。しかし、私はあなたの家庭教師でも、メンターでも、サポート窓口でもありません。私は\u003Cs>とても優しいので\u003C/s>聞かれたことにはなるべく答えるようにしていますが、それを当然のように要求されるのは、少し違うように思います。\u003C/p>\u003Cp>ついでに、ググる行為自体にも割とスキルが要ります。｢ECONNREFUSEDが出たんだけどどう治すの？｣みたいな雑な自然言語ではなく、｢ECONNREFUSED 127.0.0.1:5432 postgres:18.3-alpine｣のように、自分の環境に近い具体的なワードを並べる、英語で検索する、公式ドキュメントを優先する、GitHubのIssuesを見る、Stack Overflowは新しい順に並び替える等の工夫が必要です。\u003C/p>\u003Cp>ググれと言われて冷たいと感じる前に、自分のググり方を一度見直してみてください。それだけで、解決できる問題の幅が多分広がるかと思います。\u003C/p>\u003Ch1 id=\"h1afe451c43\">さいごに\u003C/h1>\u003Cp>正直、プログラミングなんてものはどんなに馬鹿でも時間さえかければできるようになります。\u003C/p>\u003Cp>これは、別に綺麗事として書いているのではなく、私自身がソースです。\u003C/p>\u003Cp>私自身、地頭(笑)が良いタイプでも、論理的思考力が突出しているタイプでもなく、どちらかと言えば落ちこぼれ側の人間です。覚えたての頃に書いていたコードなんて、今読み返すと冗談みたいに酷いものですし、未だに簡単なバグで数時間詰まることもざらにあります。\u003C/p>\u003Cp>何とかコードを書いて、何とかお仕事を頂いて、何とか運用できているのは、ただただ触っている時間がそれなりに長いからというだけでしょう。そこに特筆すべき才能なんてものは介在していません。\u003C/p>\u003Cp>なので、自分には才能がないからという理由で諦めるのは、的外れだと思っています。あなたに無いのは才能ではなく、ただの時間です。退屈な作業を、何百時間、何千時間と積み上げる時間が足りていないだけです。\u003C/p>\u003Cp>逆に言えば、これを積み上げる気が無いのなら、永遠にできるようにはなりませんし、｢いつか分かるようになる｣だとか、｢コツを掴めば｣みたいな、そういう商材屋の好きそうな胡散臭い魔法はありません。触った分だけ出来るようになります。\u003C/p>\u003Cp>それが面倒だと感じるのであれば、それは多分、あなたがプログラミングをそこまで好きではない、というだけの話です。それは別に悪いことではありません。世の中には、プログラミング以外にも、楽しい営みがいくらでもあります。プログラミングが特別な何かだと思い込むのは、業界の人間の自意識過剰でしょう。\u003C/p>\u003Cp>何とかしたいと思うのであれば、何とかしてください。何とかしたくないのであれば、別に何ともしなくて構いません。\u003C/p>\u003Cp>埋蔵金探しとかも新鮮で楽しそうですよ。\u003C/p>\u003Cp>それでは。\u003C/p>",[36,37,43],{"id":13,"createdAt":14,"updatedAt":15,"publishedAt":14,"revisedAt":15,"slug":16,"name":17},{"id":38,"createdAt":39,"updatedAt":40,"publishedAt":39,"revisedAt":40,"slug":41,"name":42},"8q8qyy8sz3","2025-04-29T08:44:23.406Z","2025-12-03T16:07:24.495Z","programming","プログラミング",{"id":44,"createdAt":45,"updatedAt":46,"publishedAt":45,"revisedAt":46,"slug":47,"name":48},"qfey3yw0z1","2025-04-29T08:44:41.687Z","2025-12-03T16:07:14.622Z","technology","テクノロジー","はじめにどうも、わたしです。最近、というかここ数年、タイムラインを眺めていると、「プログラミングを始めました！」「LLMでアプリを作りました！」みたいな投稿を頻繁に目にするようになりました。それ自体はとても素晴らしいことだと思いますし、新しく何かを始めようとしている人を否定するつもりは毛頭ありません",63,{"contents":52,"totalCount":63,"offset":26,"limit":25},[53],{"id":54,"createdAt":55,"updatedAt":56,"publishedAt":57,"revisedAt":56,"title":58,"content":59,"tags":60,"is_no_index":24,"summary":62},"p7zftgqr_ht","2026-06-03T17:50:57.739Z","2026-06-04T08:52:49.895Z","2026-06-03T18:04:39.359Z","商業登記電子証明書(.p12)まわりの覚書","\u003Ch1 style=\"text-align: start\" id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp style=\"text-align: start\">どうも、わたしです。\u003C/p>\u003Cp style=\"text-align: start\">最近、商業登記電子証明書の証明書ファイル本体(.p12)を扱う機会がありました。かなり苦しんだので、触っていく中で見つけた諸々を備忘録として書き残しておきます。\u003C/p>\u003Cp style=\"text-align: start\">なお、実物には当然ながら法人のクレデンシャルが含まれているので、商号、代表者氏名、シリアル番号、Subject Key Identifierといった同定可能な値はすべて伏せています。本エントリはあくまで仕様の話です。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h4d904280a0\">.p12コンテナを開ける\u003C/h1>\u003Cp style=\"text-align: start\">商業登記電子証明書は、登記・供託オンライン申請システムからPKCS#12コンテナとしてダウンロードされます。OpenSSL 3系で開く場合は\u003Ccode>-legacy\u003C/code>が必要です。\u003C/p>\u003Cpre>\u003Ccode class=\"language-bash\">openssl pkcs12 -in hogefuga.p12 -info -noout -legacy\u003C/code>\u003C/pre>\u003Cp style=\"text-align: start\">MAC=SHA-1、暗号化=3DES-CBC、Iteration=2000という構成で、2026年の基準では古風な部類です。\u003C/p>\u003Cp style=\"text-align: start\">なお、このPKCS#12の選択は法務省告示第543号の規定ではなく、登記・供託オンライン申請システム側の配布フォーマットの都合です。告示はX.509証明書のフィールド構造とCMP発行プロトコルだけを規定していて、利用者への手渡し方は何も書かれていません。仕様ではなく運用、ということは頭に入れておくとよさそうです。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"hb2cb04a84e\">中の証明書\u003C/h1>\u003Cp style=\"text-align: start\">p12を解体すると、秘密鍵1個と証明書2枚(エンドエンティティ+中間CA)が出てきます。ルートCAは入っていないので、検証側で別途取得する必要があります。\u003C/p>\u003Cp style=\"text-align: start\">エンドエンティティ証明書の基本情報はわりと普通です。\u003C/p>\u003Cul>\u003Cli>X.509 v3\u003C/li>\u003Cli>署名: sha256WithRSAEncryption\u003C/li>\u003Cli>公開鍵: RSA 2048bit\u003C/li>\u003Cli>Issuer: C=JP, O=Japanese Government, OU=Ministry of Justice, CN=Registrar of Tokyo Legal Affairs Bureau\u003C/li>\u003C/ul>\u003Cp style=\"text-align: start\">問題はSubject DNで、\u003C/p>\u003Cpre>\u003Ccode>C=JP\nO=MOJ No.XXXXXXXXXXXX\nCN=0402010000001\u003C/code>\u003C/pre>\u003Cp style=\"text-align: start\">Oが\u003Ccode>Japanese Government\u003C/code>ではなく\u003Ccode>MOJ No.{会社法人番号}\u003C/code>。\u003Cbr>CNは基本的に\u003Ccode>{役員番号}\u003C/code>で、ローマ字氏名が登録されている場合のみ\u003Ccode>{役員番号}-{氏名のローマ字}\u003C/code>の形式になります。私が触った範囲ではいずれもハイフンなしの役員番号のみでした。\u003C/p>\u003Cp style=\"text-align: start\">いずれにせよ、これを普通のクライアント証明書の感覚で扱うと、O属性を法人名だと思い込んでパースしているライブラリが、ニッコリ笑顔で会社法人番号を法人名として表示してくれます。\u003C/p>\u003Cp style=\"text-align: start\">法人名そのものは、Subject DNではなく証明書の拡張領域に格納されています。私はこれで数時間を溶かしました。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"hd5b6d68703\">本体は1.2.392.100300.1.1.3\u003C/h1>\u003Cp style=\"text-align: start\">商業登記電子証明書のすべてが詰まっているのが、法務省独自OID\u003Ccode>1.2.392.100300.1.1.3\u003C/code>です。中身はこんなASN.1構造になっています。\u003C/p>\u003Cpre>\u003Ccode class=\"language-asn1\">RegisteredCorporationInfoSyntax ::= SEQUENCE {\n    corporateName              [0] DirectoryString,  // 商号\n    registeredNumber           [1] PrintableString,  // 会社法人等番号\n    corporateAddress           [2] DirectoryString,  // 本店所在地\n    representativeDirectorName  [3] DirectoryString,  // 代表者氏名\n    representativeDirectorTitle [4] DirectoryString,  // 代表者役職\n    registryOffice             [6] DirectoryString   // 登記所\n}\u003C/code>\u003C/pre>\u003Cp style=\"text-align: start\">商号も本店も代表者氏名も役職も法人番号も登記所も、全部証明書本体に埋め込まれているわけです。登記簿照会を都度叩かなくとも、証明書を検証するだけで法人実体を照会できます。これは商業登記電子証明書独特の特徴なようで、海外の一般的なクライアント証明書とは目的がそもそも違います。\u003C/p>\u003Cp style=\"text-align: start\">ちなみに、お気づきの方もいらっしゃるかもしれませんが、タグが\u003Ccode>[0][1][2][3][4][6]\u003C/code>と並んでいて、\u003Ccode>[5]\u003C/code>が欠番になっています。告示付録2のASN.1モジュールにも\u003Ccode>[5]\u003C/code>は定義されていません。\u003C/p>\u003Cp style=\"text-align: start\">何だったんでしょうね、これ。予約とすら書かれていないあたり、運用初期に検討されて消えたフィールドなのかもしれませんが、想像の域を出ません。\u003C/p>\u003Cp style=\"text-align: start\">ついでに、もう2つの独自拡張も紹介しておきます。\u003C/p>\u003Cul>\u003Cli>1.2.392.100300.1.1.1: 日本語のUserNotice(「この証明書は、商業登記法その他の関係法令等に基づき発行されたものです。」)\u003C/li>\u003Cli>1.2.392.100300.1.1.2: 東京法務局登記官 というUTF8文字列。発行者の役職そのもの\u003C/li>\u003C/ul>\u003Cp style=\"text-align: start\">実は標準の\u003Ccode>certificatePolicies\u003C/code>(\u003Ccode>2.5.29.32\u003C/code>)拡張内にも英語のUserNoticeが入っていて、英文と和文が並存しています。同じ趣旨を文字種を変えて二重格納するというのは、ある意味で律儀ですが、実装側からすると少し迷惑な気もします。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h14c781f17c\">発行者の扱い\u003C/h1>\u003Cp style=\"text-align: start\">これは仕様を眺めていて知ったのですが、商業登記電子証明書の発行者は申請者がどこの法務局に申請しても\u003Ccode>Registrar of Tokyo Legal Affairs Bureau\u003C/code>となり、東京法務局登記官で固定なようです。\u003C/p>\u003Cp style=\"text-align: start\">申請者の管轄登記所(例えば長崎地方法務局とか)は、Issuerフィールドではなく独自拡張の\u003Ccode>registryOffice\u003C/code>に入ります。\u003C/p>\u003Cp style=\"text-align: start\">普通のPKIだと「発行者=申請を受け付けた組織」と素朴に対応していることが多いので、気をつけておくといいでしょう。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h7f21a26569\">中間CAが並存\u003C/h1>\u003Cp style=\"text-align: start\">ここもハマる方が多そうですが、商業登記認証局(CRCA1)の中間CA証明書は2世代運用されています。\u003C/p>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Cth colspan=\"1\" rowspan=\"1\">\u003Cp>世代\u003C/p>\u003C/th>\u003Cth colspan=\"1\" rowspan=\"1\">\u003Cp>有効期間\u003C/p>\u003C/th>\u003Cth colspan=\"1\" rowspan=\"1\">\u003Cp>秘密鍵使用期間\u003C/p>\u003C/th>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>旧CRCA(2022)\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>6年\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>3年\u003C/p>\u003C/td>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>新CRCA(2026)\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>10年\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>5年\u003C/p>\u003C/td>\u003C/tr>\u003C/tbody>\u003C/table>\u003Cp style=\"text-align: start\">両世代ともCommon Nameは同じ\u003Ccode>Registrar of Tokyo Legal Affairs Bureau\u003C/code>なので、CNだけでは識別できません。\u003Ca href=\"https://crca1.moj.go.jp/toukikan.html\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">シリアル番号\u003C/a>かSubject Key Identifierで判別すべきです。\u003C/p>\u003Cp style=\"text-align: start\">ちなみに、告示第543号の本文では登記官証明書は「72ヶ月/36ヶ月」、つまり6年/3年と規定されています。私が実際に触ったいくつかの証明書に含まれるCRCAは規定の倍近くに延長されていたので、告示の改正があったか、関係法令で別途上書きされているはずですが、本記事執筆時点では出典を特定できていません。詳しい方、誰か教えてください。\u003C/p>\u003Cp style=\"text-align: start\">それと、新世代では\u003Ccode>keyUsage\u003C/code>が\u003Ccode>critical\u003C/code>で付くようになっていたり、CRL Distribution Points拡張が追加されていたりと、告示の最低要件を超えた拡張が行われているようです。告示で定められているのは最低限ラインで、運用側のCP/CPSで上乗せされる感じなのかもしれません。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h7b1b74ce46\">失効確認\u003C/h1>\u003Cp style=\"text-align: start\">失効確認はAIA(\u003Ccode>1.3.6.1.5.5.7.48.1\u003C/code>)に書かれているOCSP URLを叩きます。\u003C/p>\u003Cpre>\u003Ccode class=\"language-plaintext\">http://crca.moj.go.jp/bin/dcwcgi/DC_HUSR/cert/cert\u003C/code>\u003C/pre>\u003Cp style=\"text-align: start\">新世代CAではCRLのURIも追加されていて、\u003Ccode>http://crca1.moj.go.jp/certificateRevocationList.crl\u003C/code>から取得できます。\u003C/p>\u003Cp style=\"text-align: start\">ここで地味に面白いのが、商業登記電子証明書には失効だけでなく休止届という独自概念があることです。CRLではエントリの\u003Ccode>reasonCode\u003C/code>(\u003Ccode>2.5.29.21\u003C/code>)に\u003Ccode>certificateHold (6)\u003C/code>が入り、OCSPでは\u003Ccode>CertStatus\u003C/code>が\u003Ccode>revoked\u003C/code>で返り、その\u003Ccode>revokedInfo.revocationReason\u003C/code>に\u003Ccode>certificateHold (6)\u003C/code>が入ります。代表者が交代しそうだとか、本店移転の登記が走るだとか、そのような一時停止のためのものです。商業登記電子証明書ならではの特徴と言えるでしょう。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h1afe451c43\">さいごに\u003C/h1>\u003Cp style=\"text-align: start\">商業登記電子証明書を一言でまとめると、X.509のガワを被った登記簿の抜粋です。証明書としての構造はRFC 5280に準拠しつつ、肝心の登記情報は法務省独自OIDの拡張領域に格納されていて、PKIライブラリで素直に検証すると半分しか機能を引き出せません。\u003C/p>\u003Cp style=\"text-align: start\">ところで、平成26年の告示は本体署名を\u003Ccode>sha1WithRSAEncryption\u003C/code>から\u003Ccode>sha256WithRSAEncryption\u003C/code>に切り替えるアップデート(※1)だったわけですが、p12コンテナのMACが今もSHA-1なのは正直なんとも言えない味わいがあります。中身だけ新しくしてガワが旧式というのは、行政あるあるな気もしますが、いつかはAES+PBKDF2あたりに刷新してほしい気持ちが若干あります。\u003C/p>\u003Cp style=\"text-align: start\">それでは。\u003C/p>\u003Cp style=\"text-align: start\">\u003C/p>\u003Cp style=\"text-align: start\">※1: \u003Ccode>subjectKeyIdentifier\u003C/code>や\u003Ccode>authorityKeyIdentifier\u003C/code>の補助用途では今もSHA-1が使われています\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h3de35099b3\">参考\u003C/h1>\u003Cul>\u003Cli>\u003Ca href=\"https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/d12bde7e-a950-493b-987c-0f8d4bbd1b6b/20211228_notice_article_06.pdf\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">法務省告示第543号(平成26年12月12日)\u003C/a>\u003C/li>\u003Cli>\u003Ca href=\"https://laws.e-gov.go.jp/law/339M50000010023\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">商業登記規則(昭和39年法務省令第23号)\u003C/a>\u003C/li>\u003Cli>\u003Ca href=\"https://laws.e-gov.go.jp/law/338AC0000000125\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">商業登記法(昭和38年法律第125号)\u003C/a>\u003C/li>\u003Cli>\u003Ca href=\"https://www.touki-kyoutaku-online.moj.go.jp/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">登記・供託オンライン申請システム\u003C/a>\u003C/li>\u003Cli>\u003Ca href=\"https://www.moj.go.jp/MINJI/minji06_00028.html\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">商業登記に基づく電子認証制度(法務省)\u003C/a>\u003C/li>\u003Cli>\u003Ca href=\"https://datatracker.ietf.org/doc/html/rfc5280\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">RFC 5280 Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile\u003C/a>\u003C/li>\u003Cli>\u003Ca href=\"https://datatracker.ietf.org/doc/html/rfc7292\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">RFC 7292 PKCS #12: Personal Information Exchange Syntax v1.1\u003C/a>\u003C/li>\u003Cli>\u003Ca href=\"https://datatracker.ietf.org/doc/html/rfc6960\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">RFC 6960 X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP\u003C/a>\u003C/li>\u003Cli>\u003Ca href=\"https://datatracker.ietf.org/doc/html/rfc4210\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">RFC 4210 Internet X.509 Public Key Infrastructure Certificate Management Protocol (CMP)\u003C/a>\u003C/li>\u003C/ul>\u003Cp>\u003C/p>",[61],{"id":44,"createdAt":45,"updatedAt":46,"publishedAt":45,"revisedAt":46,"slug":47,"name":48},"はじめにどうも、わたしです。最近、商業登記電子証明書の証明書ファイル本体(.p12)を扱う機会がありました。かなり苦しんだので、触っていく中で見つけた諸々を備忘録として書き残しておきます。なお、実物には当然ながら法人のクレデンシャルが含まれているので、商号、代表者氏名、シリアル番号、Subject ",5,{"url":65,"domain":66,"title":67,"description":68,"image":69,"favicon":70,"type":71},"https://github.com/tailscale/tailscale/issues/12829","github.com","Installing tailscale on a machine connected to a CGNAT network can brick it · Issue #12829 · tailscale/tailscale","What is the issue? I have a private IPv4-only network of machines/VMs/containers using 100.100.0.0/20. Thinking I'd try tailscale, I installed it and immediately lost remote access to the machine. ...","https://opengraph.githubassets.com/b85e673891ab0a881bb5b475d886bd75303fc55627461f3457e047e04251cac9/tailscale/tailscale/issues/12829","https://github.githubassets.com/favicons/favicon.svg","GENERAL",1785520627846]