GoのHTTPSリクエストで発生する「x509: certificate signed by unknown authority」エラーの修正方法

intermediate🔷 Go2026-05-15| Go 1.16以降、Linux / macOS / Windows、自己署名証明書またはプライベートCA証明書を使用するHTTPSエンドポイント

Error Message

Get "https://example.com": x509: certificate signed by unknown authority
#tls#https#x509#証明書#net/http

エラーの内容

GoのHTTPSリクエストでnet/httpパッケージを使用すると、以下のエラーが発生します:

Get "https://example.com": x509: certificate signed by unknown authority

サーバーのTLS証明書自体は正規かつ有効ですが、Goがその証明書を発行したCAを信頼していません。データのやり取りが始まる前にリクエストが失敗します。

原因

GoはシステムのCA(認証局)ストアに対してTLS証明書を検証します。以下の場合に検証が失敗します:

  • サーバーが自己署名証明書を使用している場合 — 開発環境やステージング環境でよく見られます
  • OSのトラストストアに登録されていないプライベート/内部CAが署名した証明書の場合
  • 企業プロキシやVPNがTLSインスペクションを行い、独自のCAでトラフィックを再署名している場合(Zscaler、Palo Alto NGFW、Cisco Umbrellaなど)
  • CA証明書がまったくインストールされていない最小構成のDockerコンテナscratchalpine)を使用している場合
  • システムのCAバンドルが古くなっているか、そもそも存在しない場合

修正方法1:システムトラストストアにCA証明書を追加する

本番環境や共有ホストでは、CA証明書をOSのトラストストアに一度追加するだけで済みます。そのマシン上のすべてのGoバイナリが自動的に読み込みます — コードの変更は不要です。

Linux(Debian/Ubuntu)

# CA証明書(PEM形式)をトラストストアにコピーする
sudo cp your-ca.crt /usr/local/share/ca-certificates/your-ca.crt
sudo update-ca-certificates

Linux(RHEL/CentOS/Fedora)

sudo cp your-ca.crt /etc/pki/ca-trust/source/anchors/your-ca.crt
sudo update-ca-trust

macOS

sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain your-ca.crt

証明書を追加したら、Goアプリケーションを再起動してください。システムストアはリクエストごとではなく、起動時に読み込まれます。

修正方法2:CA証明書をプログラムで読み込む

システムのトラストストアを変更できない場合は、GoのコードでCA証明書を直接読み込みます。共有サーバー、読み取り専用コンテナ、OSの変更が許可されていない環境で有効な方法です。

package main

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    // CA証明書ファイル(PEM形式)を読み込む
    caCert, err := os.ReadFile("your-ca.crt")
    if err != nil {
        panic(err)
    }

    // システムプールに追加する
    caCertPool, err := x509.SystemCertPool()
    if err != nil {
        // フォールバック:空のプールを作成する
        caCertPool = x509.NewCertPool()
    }
    caCertPool.AppendCertsFromPEM(caCert)

    // 拡張プールを使用するHTTPクライアントを構築する
    client := &http.Client{
        Transport: &http.Transport{
            TLSClientConfig: &tls.Config{
                RootCAs: caCertPool,
            },
        },
    }

    resp, err := client.Get("https://example.com")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}

CA証明書はバイナリと一緒に配布されます。OSの変更不要、システム全体への影響もありません。

修正方法3:DockerコンテナのCA証明書不足を解消する

最小構成のベースイメージ(scratchalpinedistroless)にはCA証明書がまったく含まれていません。バイナリは正常にコンパイルされますが、実行時に最初のHTTPS呼び出しでクラッシュします。

オプションA — Alpineにca-certificatesをインストールする

FROM alpine:3.19
RUN apk add --no-cache ca-certificates
COPY your-app /app
ENTRYPOINT ["/app"]

オプションB — ビルダーステージからCA証明書をコピーする(scratchイメージの場合)

FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o app .

FROM scratch
# ビルダーからシステムCAバンドルをコピーする
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /src/app /app
ENTRYPOINT ["/app"]

修正方法4:TLS検証をスキップする(開発環境のみ)

この方法も存在します。ローカルテスト専用にしてください。本番環境でInsecureSkipVerify: trueを使用すると、中間者攻撃を行うサーバーを含むあらゆるサーバーが任意の証明書を提示でき、コードは無条件にそれを受け入れてしまいます。

client := &http.Client{
    Transport: &http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true, // ⚠️ 開発環境のみ
        },
    },
}

本番コードでこれを見つけた場合は、修正方法1または修正方法2で根本原因を解決してください。

修正方法5:企業プロキシ/VPNによるTLSインスペクション

典型的なサインとして、同じネットワーク上の同僚はエラーが発生していないのに自分だけ発生している場合があります。プロキシがTLSトラフィックを傍受し、独自のCAで再署名している可能性が高いです。ITまたはセキュリティチームにプロキシのルートCA証明書を問い合わせ、その証明書で修正方法1または修正方法2を適用してください。

サーバーが実際に提示している証明書を確認するには、次のコマンドを実行します:

openssl s_client -connect example.com:443 < /dev/null 2>&1 | openssl x509 -noout -issuer -subject

発行者にDigiCertやLet's EncryptではなくBoの会社名や*「Zscaler Root CA」*が表示されている場合、それが信頼する必要のあるプロキシ証明書です。

修正の確認

Goプログラムを再実行してください。TLSエラーが表示されなければ修正成功です。手動で確認するには、OpenSSLを直接使用します:

# 詳細出力でプログラムを実行する
go run -v your_main.go

# CAファイルに対して証明書チェーンを検証する
openssl s_client -connect example.com:443 -CAfile your-ca.crt

OpenSSLがVerify return code: 0 (ok)を返せば、チェーンは正常です。Goも受け入れます。

予防策

  • 内部CAをバージョン管理に保存する:企業のCA証明書を共有リポジトリや構成管理ツール(Ansible、Chef、Puppet)に配置します。新しいホストはプロビジョニング時に自動的に取得できるため、手動作業が不要になります。
  • 外部へのHTTPSリクエストを行うDockerイメージには必ずca-certificatesを含める:本番インシデントが発生してから不足に気づくのは避けましょう。
  • CIでInsecureSkipVerifyを禁止する:1行のgrepでマージ前に検出できます — PRパイプラインでgrep -r InsecureSkipVerify ./を実行します。
  • 環境変数からCAパスを読み込む:同じバイナリが開発環境(自己署名証明書)と本番環境(パブリックCA)の両方でコードの変更なしに動作するようになります。

Related Error Notes