Go で x509: certificate relies on legacy Common Name field, use SANs instead を修正する

intermediate🔒 SSL/TLS2026-05-11| Go 1.15以降、任意のOS(Linux、macOS、Windows)、TLS/HTTPS クライアント接続

Error Message

x509: certificate relies on legacy Common Name field, use SANs instead
#golang#ssl#x509#san#tls

TL;DR

証明書に Common Name (CN) フィールドしかなく、Subject Alternative Name (SAN) 拡張がありません。Go 1.15 からSANが必須になりました。SANを含めて証明書を再生成すれば解決します。

エラー内容

x509: certificate relies on legacy Common Name field, use SANs instead

このエラーは、GoアプリがTLSクライアントとして、SAN拡張のない証明書を持つサーバーに接続したときに発生します。Go 1.15からRFC 2818が厳格に適用されるようになり、ホスト名の検証はCNではなくSANを通じて行う必要があります。ブラウザはずっと前にCNのみのサポートを廃止しており、Go 1.15でそれに追随しました。

よく見られるケース:

  • 古い openssl req ワンライナーで生成した自己署名証明書を使う内部サービス
  • -ext フラグなしで生成された開発用証明書
  • SAN要件以前の古いレガシー企業PKI
  • CNのみを設定していた2018年以前の古いツール

根本原因

古いTLSクライアントにはフォールバックがありました。証明書にSANがない場合、代わりに Common Name に対してホスト名を照合していました。Go 1.15ではこのフォールバックが完全に削除されました。これ以降、証明書は接続先のホストに一致する Subject Alternative Name のDNSエントリ(またはIPアドレス)を持つ必要があります。

次のコマンドを実行して、証明書にSANがないことを確認します:

# ライブサーバーに対して確認する
openssl s_client -connect yourhost:443 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative Name"

# またはローカルの証明書ファイルを検査する
openssl x509 -in server.crt -noout -text | grep -A1 "Subject Alternative Name"

出力が空(DNS:IP Address: の行がない)であれば問題が確認できます。

修正1 — SANを含めて証明書を再生成する(推奨)

再生成が唯一の根本的な修正方法です。以下に3つの方法を紹介します。

オプションA:設定ファイルを使ったopenssl

san.cnf を作成します:

[req]
default_bits       = 2048
prompt             = no
default_md         = sha256
distinguished_name = dn
req_extensions     = v3_req

[dn]
CN = yourhost.internal

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = yourhost.internal
DNS.2 = localhost
IP.1  = 127.0.0.1

次に鍵と証明書を生成します:

openssl req -x509 -nodes -days 825 \
  -newkey rsa:2048 \
  -keyout server.key \
  -out server.crt \
  -config san.cnf \
  -extensions v3_req

オプションB:mkcert(ローカル開発に最速)

mkcert はローカルCAをセットアップし、システムのトラストストアに追加して、適切なSANを組み込みます。設定ファイルは不要です:

brew install mkcert       # macOS
# または: apt install mkcert  # Debian/Ubuntu

mkcert -install
mkcert yourhost.internal localhost 127.0.0.1

yourhost.internal+2.pemyourhost.internal+2-key.pem が生成され、OSとブラウザで最初から信頼されます。

オプションC:GoのcryptO/x509でプログラム的に生成する

package main

import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "crypto/x509"
    "crypto/x509/pkix"
    "encoding/pem"
    "math/big"
    "net"
    "os"
    "time"
)

func main() {
    key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)

    template := &x509.Certificate{
        SerialNumber: big.NewInt(1),
        Subject:      pkix.Name{CommonName: "localhost"},
        NotBefore:    time.Now(),
        NotAfter:     time.Now().Add(365 * 24 * time.Hour),
        KeyUsage:     x509.KeyUsageDigitalSignature,
        ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
        // SANs — Goが要求する項目
        DNSNames:    []string{"localhost", "yourhost.internal"},
        IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
    }

    certDER, _ := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)

    certFile, _ := os.Create("server.crt")
    pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certDER})
    certFile.Close()

    keyDER, _ := x509.MarshalECPrivateKey(key)
    keyFile, _ := os.Create("server.key")
    pem.Encode(keyFile, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDER})
    keyFile.Close()
}

修正2 — 一時的な回避策(Go 1.15〜1.16のみ)

証明書の更新を待っている間の緊急対応として、GODEBUG フラグで古いCNフォールバックを再有効化できます。ただし、これは短期的な対応にすぎません:

GODEBUG=x509ignoreCN=0 go run main.go

またはコードで、TLS呼び出しの前に設定します:

import "os"
os.Setenv("GODEBUG", "x509ignoreCN=0")

重要な制限: x509ignoreCN=0 はGo 1.17で削除されました。1.17以降では何も効果がありません。証明書を修正してください。

修正3 — 検証を完全にスキップする(テスト専用)

両端を自分で管理している自動テストや内部ツール向け:

import (
    "crypto/tls"
    "net/http"
)

client := &http.Client{
    Transport: &http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true, // 本番環境では絶対に使わない
        },
    },
}

InsecureSkipVerify: true はホスト名・有効期限・信頼チェーンを含むすべての証明書検証を無効化します。ローカルテストでは問題ありませんが、それ以外の環境ではセキュリティホールになります。

修正の確認

再生成後、SANが証明書に正しく含まれているか確認します:

openssl x509 -in server.crt -noout -text | grep -A2 "Subject Alternative Name"

期待される出力:

X509v3 Subject Alternative Name:
    DNS:yourhost.internal, DNS:localhost, IP Address:127.0.0.1

Goプログラムを実行してエラーが消えているか確認します。簡単なライブテストには次を使用します:

curl --cacert server.crt https://yourhost.internal:8443/health

200 OK が返ればTLSハンドシェイクが正常に完了したことを意味します。

まとめ

  • Go 1.15以降ではSANが必須です。CNのみの証明書は一切受け付けられません。
  • 設定ファイルを使った opensslmkcert、またはGoの crypto/x509 で再生成してください。
  • GODEBUG=x509ignoreCN=0 はGo 1.15〜1.16のみで一時的に有効です。
  • InsecureSkipVerify はテスト用であり、本番環境では使用しないでください。

Related Error Notes