[{"data":1,"prerenderedAt":71},["ShallowReactive",2],{"article-p7zftgqr_ht":3,"prev-article-p7zftgqr_ht":22,"next-article-p7zftgqr_ht":45},{"contents":4,"totalCount":20,"offset":21,"limit":20},[5],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":9,"revisedAt":8,"title":10,"content":11,"tags":12,"is_no_index":19},"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>",[13],{"id":14,"createdAt":15,"updatedAt":16,"publishedAt":15,"revisedAt":16,"slug":17,"name":18},"qfey3yw0z1","2025-04-29T08:44:41.687Z","2025-12-03T16:07:14.622Z","technology","テクノロジー",false,1,0,{"contents":23,"totalCount":44,"offset":21,"limit":20},[24],{"id":25,"createdAt":26,"updatedAt":27,"publishedAt":27,"revisedAt":27,"title":28,"content":29,"tags":30,"is_no_index":19,"summary":43},"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>",[31,37],{"id":32,"createdAt":33,"updatedAt":34,"publishedAt":33,"revisedAt":34,"slug":35,"name":36},"wia4slp55q","2025-04-28T07:14:14.541Z","2025-12-03T16:08:13.798Z","thoughts","独り言",{"id":38,"createdAt":39,"updatedAt":40,"publishedAt":39,"revisedAt":40,"slug":41,"name":42},"lte0t59xm8sb","2025-05-02T16:12:38.708Z","2025-12-03T16:06:52.753Z","network","ネットワーク","はじめにTailscaleはネットワークの知識がない人が使うものだと思っていて、内心ずっと冷笑しているのですが、悪い噂をあまり聞かないので本当に悲しいです。用途に応じて使い分けろという話なんだろうとは思います。思いますが、他人の環境にアクセスしたいときに「まずTailscaleを入れて〜」みたいなこ",64,{"contents":46,"totalCount":70,"offset":21,"limit":20},[47],{"id":48,"createdAt":49,"updatedAt":50,"publishedAt":51,"revisedAt":50,"title":52,"content":53,"tags":54,"is_no_index":19,"summary":69},"oy69jxht12","2026-06-19T18:38:58.987Z","2026-06-26T14:48:16.179Z","2026-06-19T18:48:10.255Z","Hide My Emailのドメインが変わるので、また悩んでいる","\u003Ch1 id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp>どうも、わたしです。\u003C/p>\u003Cp>以前、\u003Ca href=\"https://mq1.dev/entry/svgkndwg3ng9\">独自ドメインでのメールアドレス運用をやめ、Hide My Emailに移行した話\u003C/a>という記事を書きました。「自前運用もSESも全部やめて全てをHide My Emailに寄せたよ〜」という話です。\u003C/p>\u003Cp>で、そのHide My Emailなんですが、先日、生成されるアドレスのドメインが\u003Ccode>@icloud.com\u003C/code>から\u003Ccode>@private.icloud.com\u003C/code>に変わると発表されました。すでに発行済みのアドレスは引き続き転送されるらしいので、過去の登録が消えてしまうわけではないのですが、これから作るぶんが別ドメインになる時点で、わたしにとっての価値の大半は消し飛びます。\u003C/p>\u003Cp>\u003Ca href=\"https://developer.apple.com/news/?id=sus6t6ab&amp;7194ef805fa2d04b0f7e8c9521f97343\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https://developer.apple.com/news/?id=sus6t6ab&amp;7194ef805fa2d04b0f7e8c9521f97343\u003C/a>\u003C/p>\u003Cp>さて、困りました。\u003C/p>\u003Ch1 id=\"ha05bbba395\">なにが困るのか\u003C/h1>\u003Cp>わたしがHide My Emailを愛用していた理由は、大きく二つあります。\u003C/p>\u003Cp>プライマリのアドレスと紐付けずにサービスごとに使い分けられること、そして\u003Ccode>icloud.com\u003C/code>のドメインパワーに肖れることです。\u003C/p>\u003Cp>特に後者が大きくて。\u003Cbr>そもそもHide My Emailを嬉しく思っていたのは、生成されるアドレスが普通のiCloudユーザと見分けがつかなかったからでした。受け手からすればただのiCloudユーザーにしか見えないので、後述する特定の大手ドメインしか受け付けないみたいな邪悪な実装も平然と通過できていました。それが\u003Ccode>@private.icloud.com\u003C/code>になると、受け手がHide My Emailを判別できるようになってしまいます。\u003C/p>\u003Cp>要するに、機能が成立していた前提をApple自身が手放しにきているわけです。プライバシ機能を名乗っておいてこれは、なかなかのものだなと思います。\u003C/p>\u003Cp>で、世の中には、GmailとiCloud(国内だとヘンテコ仕様なキャリアメールなんかも)以外のドメインを弾くようになっているサービスがそこそこあります。\u003Cs>Pi○tLinkなんかがそうですね。\u003C/s>こういう邪悪な実装のところでは、\u003Ccode>icloud.com\u003C/code>が使えること自体が最大にして唯一の利点でした。正直、わたしはこの一点のためだけにiCloud+へ課金していたと言っても過言ではありません。\u003C/p>\u003Cp>プライバシがどうとかいう高尚な理由ではなく、純粋に弾かれないための月額だったので、ここがなくなってしまうのはとても苦しい。\u003C/p>\u003Ch1 id=\"hf58740672c\">そもそも独自ドメインのメールって旨味あるの\u003C/h1>\u003Cp>「じゃあ独自ドメインに戻せば」という話になりそうですが、わたしはこのご時世に個人で独自ドメインのメールを持つ旨味、あんまりないと思っています。理由は二つ。\u003C/p>\u003Cp>一つは、メールサーバを自前で持つハードルが高いこと。\u003Cbr>ここで言うハードルは、構築の手間のことではありません。安定して長期運用できること、そしてレピュテーションを健全に保ち続けられること。実際のところ、メールサーバを立てるだけなら誰でもできるのですが、問題はそこから先で、送信ドメイン認証を整えて、IPを腐らせないように気を遣って、ある日突然どこかにブロックされても対処し続ける維持のほうが本体なんですよね。一度評判を落とすと戻すのも大変だし、これを個人で延々とやる価値があるかというと、正直微妙です。\u003C/p>\u003Cp>そもそもASN単位でブロックリスト入りすることも往々にしてあるので、根本的解決を図るにはASNを取得しIP割当を受けるしかない気がします。あまりにも不毛です。\u003C/p>\u003Cp>もう一つは、結局外部のプロバイダに乗せるなら独自ドメインの旨味は薄いこと。\u003Cbr>SESなりWorkspaceなりに任せるなら、配送やレピュテーションの面倒は向こうが見てくれる代わりに、自分が握ってるのはドメイン名といざとなれば乗り換えられる安心感くらいになります。それはそれで価値がないこともないのですが、Hide My Emailの大手のドメインに乗れることとはそもそも別の話です。\u003C/p>\u003Cp>もちろん利点もあって、スパムが来たときにどのサービスがお漏らしたか分かるとか、普段使いのアドレスを隠せるとか、管理が幾分か楽になるとか。でも正直、どれも過去のHide My Emailを超えることはないように思います。\u003C/p>\u003Ch1 id=\"hba13ad79dc\">Gmailのサブアドレスも微妙\u003C/h1>\u003Cp>Gmailのエイリアス(※1)を使う手もあります。\u003C/p>\u003Cp>ただこれ、同一人物への到達性を保証しなくていいスパムであれば、local partのuser部だけ抽出して(厳密ではないにせよ)送れてしまうんですよね。\u003Cs>少なくとも私ならそういう実装をしますし、多くの人がそう考えると思います。\u003C/s>Separator character sequence以降を捨てれば届いてしまうので、使い捨てアドレスとしては心許ない。かなり微妙。\u003C/p>\u003Ch1 id=\"h287541f080\">で、結局どうするか決まってない\u003C/h1>\u003Cp>整理すると、わたしが欲しいのは三つです。プライマリのアドレスを隠せること、サービスごとに分けられること、そして邪悪な実装を通れること。最初の二つは代替がいくらでもあるのですが、問題は三つめで、これを満たせる選択肢が驚くほど見つかりません。\u003C/p>\u003Cp>一応、候補は一通り眺めてみました。\u003C/p>\u003Cp>\u003Ca href=\"https://addy.io/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">addy.io\u003C/a>や\u003Ca href=\"https://simplelogin.io/ja/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">SimpleLogin\u003C/a>のようなエイリアスサービスは、マスキングも使い分けも完璧。しかし、相手に渡すアドレスは結局そのサービス自身のドメインになるので、\u003Ccode>@addy.io\u003C/code>とか\u003Ccode>@simplelogin.io\u003C/code>をGmail/iCloud/ヘンテコキャリアメールしか通さない許可リストが受け入れてくれるわけがありません。ついでにSimpleLoginはProton傘下で、わたしはProtonが好きではないので却下。\u003C/p>\u003Cp>独自ドメインを自前運用したりWorkspaceに載せたりする手も、同じ壁に当たります。受け手が見てるのはドメイン名の文字列であって、誰がホストしてるかではないため、どれだけ真っ当に運用されてようと、\u003Ccode>icloud.com\u003C/code>でも\u003Ccode>gmail.com\u003C/code>でもない以上、リテラル照合の前では無力です。Googleのインフラに乗せようが、自分のドメインである事実は変わらないので。\u003C/p>\u003Cp>iCloudの素のエイリアス(Hide My Emailではなく、\u003Ccode>@icloud.com\u003C/code>を最大3つ作れるやつ)は、ドメインが本物の\u003Ccode>icloud.com\u003C/code>のままなので許可リストは通ります。これはうれしい。しかし、3つしか作れないうえ、3つ埋まった状態で1つ消すと次を作るまで7日待たされるようで、使い捨てとして回すには微妙です。\u003C/p>\u003Cp>規約上どうかは知りませんが、転送専用のGmailアカウントを量産する手も思いつきました。\u003Cs>(思いついただけでやってないので叩かないでください)\u003C/s>これなら渡すのは正真正銘の\u003Ccode>@gmail.com\u003C/code>で許可リストも確実に通るし、数も稼げそうです。しかし、アカウントごとに電話番号認証だの複数アカウントの取り回しだのが付いてくる上、Googleの機嫌次第でまとめて凍結される可能性も拭えず、得られる体験のわりに管理コストとリスクが釣り合っていません。無念。\u003C/p>\u003Cp>という具合に、どれを取っても過去のHide My Emailには届かないんです。結局わたしが失おうとしてるのは、「大手のドメインに、ほぼ無限に、片手間で乗れる」という、よく考えるとかなり贅沢な状態だったんだなと。\u003Cbr>しかもApple側が仕様としてやめると言ってる以上、こっちの工夫でどうこうできる話でもなく。すごく普通に困ってます。\u003C/p>\u003Cp>そもそもみなさん、メールアドレスの運用ってどうしてるんでしょう？\u003Cbr>いい感じの方法があったら本当に教えてほしいです。\u003C/p>\u003Cp>\u003C/p>\u003Cp>\u003C/p>\u003Chr>\u003Cp>※1 RFC 5233のsubaddressingは、Separator character sequence + Detailであって、これがエイリアスでないことは理解しています。が、(腹立たしいことに)慣習上そう呼ばれることが多い(らしい)のでここでもそう呼んでます。\u003C/p>\u003Cp>蛇足ですが、&quot;Separator character sequence&quot;という言い方をすると、何らかの形で明確に分離された構造になっているように聞こえますが、実際にRFCが言ってるのは「UserにDetailを加えたアドレスをUserにルーティングできる」くらいのことでしかなくて、RFC 5321/5322が「local partの解釈は受け手のソフトウェア次第」ってスタンスなのに対して、RFC 5233はlocal partの形式の例として「local part=userってわけじゃなくてぇ」みたいな話をしてるに過ぎません。広げてるように見えて制限してる規格かと思いきや、その実なにも制限してない用語と用例が出されてるだけのものなので誤解しないようにしてくださいね。\u003C/p>\u003Cp>そもそもエイリアスは原初から全く別の機能の名称として存在してるので、この呼び方にはずっと不満があります。\u003C/p>",[55,56,62,63],{"id":14,"createdAt":15,"updatedAt":16,"publishedAt":15,"revisedAt":16,"slug":17,"name":18},{"id":57,"createdAt":58,"updatedAt":59,"publishedAt":58,"revisedAt":59,"slug":60,"name":61},"fwj_nwhj1-s","2025-04-30T04:55:28.953Z","2025-12-03T16:07:03.591Z","server","サーバー",{"id":32,"createdAt":33,"updatedAt":34,"publishedAt":33,"revisedAt":34,"slug":35,"name":36},{"id":64,"createdAt":65,"updatedAt":66,"publishedAt":65,"revisedAt":66,"slug":67,"name":68},"4oy2jc8mdg","2025-04-28T07:14:01.179Z","2025-12-03T16:08:24.495Z","diary","日記","はじめにどうも、わたしです。以前、独自ドメインでのメールアドレス運用をやめ、Hide My Emailに移行した話という記事を書きました。「自前運用もSESも全部やめて全てをHide My Emailに寄せたよ〜」という話です。で、そのHide My Emailなんですが、先日、生成されるアドレスの",4,1783975274073]