状況
プレイブックで get_url や uri を使ってファイルをダウンロードしたり、内部APIをポーリングしたりしています。一見問題なさそうに見えますが、ターミナルに次のエラーが表示されます:
FAILED! => {
"msg": "Status code was -1 and not [200]: Request failed: "
}
ステータスコード -1 は接続が確立できなかったことを意味します。よくある原因:
- 自己署名証明書を使用している内部サーバー
- 企業のSSLインスペクションプロキシ(Zscaler、Forcepoint、SSL bumpを使ったSquid)
- PythonがCAとして認識していない内部CAで署名された証明書を使うステージング/開発環境
- 誰も気づかなかった期限切れのサーバー証明書 — Ansibleが検出するまで
Python/Ansibleが証明書を拒否する理由
Ansibleの uri および get_url モジュールは内部でPythonの urllib を使用しています。システムのCAバンドル、またはインストールされていれば certifi パッケージのバンドルに対してSSL証明書を検証します。サーバーの証明書がそのバンドル内のCAによって署名されていない場合、Pythonは接続を切断してステータス -1 を返します。プロンプトも警告も出さず、ただ強制終了されます。
ブラウザはこれを別の方法で処理します — 独自のトラストストアを持ち、クリックスルーの警告を表示します。Pythonにはそのような選択肢がありません。
応急処置 — 検証を無効化する(注意して使用)
管理された内部ネットワーク上で今すぐ動かす必要がありますか? validate_certs: false を追加してください:
- name: Download file from internal server
get_url:
url: "https://internal.example.com/files/package.tar.gz"
dest: /tmp/package.tar.gz
validate_certs: false
- name: Hit internal API
uri:
url: "https://internal-api.example.com/health"
method: GET
validate_certs: false
register: api_response
**これはSSL検証を完全に無効化します。**ファイアウォール内の内部ツールには許容できます。インターネットや機密データに関わるものには絶対に使用しないでください — MITM攻撃に対して無防備になります。
恒久的な解決策 — CA証明書を追加する
正しいアプローチは、内部CAをPythonに信頼させることです。セットアップに応じて3つの選択肢があります。
オプション1:AnsibleにCAバンドルを指定する
ca_path パラメーターを使用すると、タスクごとに信頼する証明書を正確に指定できます:
- name: Download with custom CA
get_url:
url: "https://internal.example.com/files/package.tar.gz"
dest: /tmp/package.tar.gz
ca_path: /etc/ssl/certs/internal-ca.crt
- name: URI with custom CA
uri:
url: "https://internal-api.example.com/status"
ca_path: /etc/ssl/certs/internal-ca.crt
CA証明書はインフラまたはセキュリティチームから入手してください。自己署名サーバー証明書の場合は、コントロールノードから直接取得します:
# Grab the cert from the server
openssl s_client -connect internal.example.com:443 -showcerts </dev/null 2>/dev/null | \
openssl x509 -outform PEM > /etc/ssl/certs/internal-ca.crt
オプション2:CAをシステムトラストストアに追加する
一度追加すれば、Ansible、curl、Pythonスクリプトなど — すべてが自動的に認識します。繰り返し使用する場合に最適な選択肢です。
Ubuntu/Debianの場合:
sudo cp internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt
sudo update-ca-certificates
RHEL/CentOS/Rockyの場合:
sudo cp internal-ca.crt /etc/pki/ca-trust/source/anchors/internal-ca.crt
sudo update-ca-trust
完了したら、タスクから validate_certs: false や ca_path を削除してください — システムトラストストアが処理を引き継ぎます。
オプション3:環境変数でCAバンドルを設定する
root権限がない場合やコンテナで実行している場合は、プレイブックの environment ブロックに REQUESTS_CA_BUNDLE を設定します:
- name: Download with CA via env var
get_url:
url: "https://internal.example.com/files/package.tar.gz"
dest: /tmp/package.tar.gz
environment:
REQUESTS_CA_BUNDLE: /path/to/internal-ca.crt
恒久的な設定として、Ansibleを起動するシェルプロファイル(例:~/.bashrc や /etc/profile.d/ansible-ca.sh)にエクスポートします:
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/internal-ca.crt
export SSL_CERT_FILE=/etc/ssl/certs/internal-ca.crt
企業プロキシ(SSLインスペクション)
ZscalerなどのプロキシはHTTPSトラフィックを傍受し、すべての接続をプロキシ自身のCAで再署名します。Pythonはそのプロキシ証明書を見て、信頼できないと判断して接続を切断します。
解決策:ITチームからプロキシのルートCAを入手し、上記のオプション2を使って追加してください。そのCAがトラストストアに入れば、プロキシ経由のすべてのHTTPS通信が機能します — 検証バイパスは不要です。
まず、プロキシが実際に原因かどうか確認します:
# Check what cert you're actually getting
openssl s_client -connect internal.example.com:443 </dev/null 2>/dev/null | openssl x509 -text -noout | grep -E "Issuer|Subject"
Issuer にサーバーの実際のCAではなくプロキシベンダー(Zscaler Inc のような名称)が表示されていれば、それが原因です。
修正の確認
フルプレイブックを実行する前に、コントロールノードでテストします:
# Quick Python check
python3 -c "
import urllib.request
response = urllib.request.urlopen('https://internal.example.com')
print(response.status)
"
# Or inspect the cert chain with curl
curl -v https://internal.example.com 2>&1 | grep -E "SSL|certificate|verify"
次に、最小限のプレイブックを実行してAnsibleが正常に動作することを確認します:
- name: Verify SSL fix
hosts: localhost
gather_facts: false
tasks:
- name: Check endpoint
uri:
url: "https://internal.example.com/health"
method: GET
register: result
- debug:
msg: "Status: {{ result.status }}"
validate_certs: false なしで Status: 200 が返れば — 完了です。
チェックリスト
- 実際のCA証明書を取得する — 検証を無効化するだけでは済ませない
- Ubuntuの場合:
update-ca-certificates;RHELの場合:update-ca-trust - タスクレベルの制御には
ca_pathを、グローバルな修正にはシステムトラストストアを使用する - 企業プロキシの背後にいる場合は、サーバー証明書ではなくプロキシのルートCAをITチームから入手する
- まず
openssl s_clientを実行して、どの証明書チェーンが使われているか正確に確認する

