86 lines
4.3 KiB
YAML
86 lines
4.3 KiB
YAML
# 可复用:TLS 握手 + SNI,openssl s_client;输出 [OC-ASSERT](Epic 3.3 入口侧 TLS 证据)。
|
||
#
|
||
# 必填:verify_tls_connect_host(建议 IP 或解析到的入口地址)、verify_tls_servername(SNI,常同 HTTP Host)
|
||
# 可选:verify_tls_port(默认 443)、verify_tls_timeout_sec(默认 10)、
|
||
# verify_tls_expect_subject_substring(若设置,则 x509 subject 须包含该子串,grep -F)、
|
||
# verify_tls_expect_san_substring(若设置,则 SAN 扩展文本须包含该子串)、
|
||
# verify_tls_cafile(若设置,s_client 增加 -CAfile;路径须在执行主机存在)、
|
||
# verify_tls_insecure_skip_verify(默认 false;true 时仅审计标注「不对链做强断言」,仍解析对端呈现证书)、
|
||
# verify_tls_assertion_label(默认 tls_sni_handshake)
|
||
|
||
- name: Assert tls-openssl-sni required vars
|
||
ansible.builtin.assert:
|
||
that:
|
||
- verify_tls_connect_host is defined
|
||
- (verify_tls_connect_host | trim | length) > 0
|
||
- verify_tls_servername is defined
|
||
- (verify_tls_servername | trim | length) > 0
|
||
fail_msg: "verify_common tls-openssl-sni:需设置 verify_tls_connect_host 与 verify_tls_servername"
|
||
|
||
- name: TLS handshake + certificate subject (openssl s_client)
|
||
ansible.builtin.shell: |
|
||
set -euo pipefail
|
||
assertion={{ (verify_tls_assertion_label | default('tls_sni_handshake')) | quote }}
|
||
host={{ verify_tls_connect_host | trim | quote }}
|
||
port={{ verify_tls_port | default(443) | int }}
|
||
sni={{ verify_tls_servername | trim | quote }}
|
||
timeout={{ verify_tls_timeout_sec | default(10) | int }}
|
||
expect={{ (verify_tls_expect_subject_substring | default('') | trim) | quote }}
|
||
expect_san={{ (verify_tls_expect_san_substring | default('') | trim) | quote }}
|
||
cafile={{ (verify_tls_cafile | default('') | trim) | quote }}
|
||
insecure={{ ('1' if (verify_tls_insecure_skip_verify | default(false) | bool) else '0') | quote }}
|
||
|
||
extra_ca=""
|
||
if [ -n "$cafile" ]; then
|
||
if [ ! -f "$cafile" ]; then
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=cafile result=fail reason=missing_file path=${cafile}"
|
||
exit 1
|
||
fi
|
||
extra_ca="-CAfile ${cafile}"
|
||
fi
|
||
|
||
if [ "$insecure" = "1" ]; then
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=insecure_skip_verify value=1 note=peer_cert_only_lab_or_troubleshoot"
|
||
fi
|
||
|
||
raw=$(echo | timeout "$timeout" openssl s_client -connect "${host}:${port}" -servername "$sni" ${extra_ca} </dev/null 2>&1 || true)
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=s_client_log excerpt"
|
||
echo "$raw" | tail -25
|
||
|
||
subj=$(echo "$raw" | openssl x509 -noout -subject 2>/dev/null || true)
|
||
if [ -z "$subj" ]; then
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=subject result=fail reason=no_certificate_or_handshake"
|
||
exit 1
|
||
fi
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=subject value=${subj}"
|
||
|
||
dates=$(echo "$raw" | openssl x509 -noout -dates 2>/dev/null || true)
|
||
not_after=$(echo "$dates" | grep '^notAfter=' | cut -d= -f2- | tr -d '\r' || true)
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=cert_not_after value=${not_after:-unknown}"
|
||
|
||
san=$(echo "$raw" | openssl x509 -noout -ext subjectAltName 2>/dev/null || true)
|
||
if [ -z "$(echo "$san" | tr -d '[:space:]')" ]; then
|
||
san=$(echo "$raw" | openssl x509 -noout -text 2>/dev/null | awk '/X509v3 Subject Alternative Name:/{getline; print; exit}' || true)
|
||
fi
|
||
san_log=$(echo "$san" | tr '\n\r\t' ' ' | cut -c1-240)
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=san excerpt=${san_log:-<none>}"
|
||
|
||
if [ -n "$expect" ]; then
|
||
echo "$subj" | grep -Fq -- "$expect" || {
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=subject_match result=fail expected_substring=${expect}"
|
||
exit 1
|
||
}
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=subject_match result=ok"
|
||
fi
|
||
|
||
if [ -n "$expect_san" ]; then
|
||
echo "$san" | grep -Fq -- "$expect_san" || {
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=san_match result=fail expected_substring=${expect_san}"
|
||
exit 1
|
||
}
|
||
echo "[OC-ASSERT] assertion=${assertion} phase=tls probe=san_match result=ok"
|
||
fi
|
||
args:
|
||
executable: /bin/bash
|
||
changed_when: false
|