| Server IP : 104.21.21.239 / Your IP : 216.73.216.11 Web Server : Apache/2.4.68 (Amazon Linux) OpenSSL/3.5.5 System : Linux ip-172-31-69-123.ec2.internal 6.1.176-223.369.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Jul 24 13:34:27 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /lib/python3.9/site-packages/cfnbootstrap/ |
Upload File : |
# ==============================================================================
# Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""
OS dispatcher for the override CA install/trust subsystem.
Public surface:
ensure_ca_override_installed() -- safe + cheap to call from every cfn-*
entrypoint at process startup. Idempotent.
Linux: no-op (the existing _certs path
points the stdlib ssl module at the
override PEM file directly). Windows:
delegates to _ca_install_win.install_or_rotate
which installs/rotates trust in the
Windows cert stores via certutil.exe
subprocess calls.
CaOverrideError -- the single exception class raised by this
subsystem. Distinguish failure modes via
the .kind string attribute (NOT subclass).
cfn-* entrypoints MUST NOT catch this
error -- letting it terminate the process
with full traceback is the documented
behaviour so on-call sees the root cause.
Hard invariants enforced here:
* Never imports `ssl` or `OpenSSL`. The Windows path uses subprocess only.
* Linux behaviour is byte-for-byte unchanged: PEM absent => no-op; PEM
present => no-op (the request-time _certs.resolve_ca_bundle() already
hands the PEM to the stdlib ssl module).
* The no-override commercial Windows path is byte-for-byte unchanged:
missing PEM short-circuits BEFORE any hashing or install work.
* Inclusive language only (per the Inclusive Tech word list).
"""
import logging
import os
from typing import Optional
# Module-level logger consistent with the rest of the cfnbootstrap package.
log = logging.getLogger('cfn.init')
# Greppable prefix used on every log line emitted by this subsystem.
_LOG_PREFIX = '[CaOverrideInstall]'
class CaOverrideError(Exception):
"""Single exception class for every failure in the override-CA subsystem.
Distinguish failure modes via the ``.kind`` string attribute (one of the
values listed in the design's section 4). Callers MUST NOT branch on the
exception subclass; branch on ``.kind`` only.
Attributes:
kind: One of the canonical kind strings.
message: Human-readable message. By convention starts with
``[CaOverrideInstall]`` and ends with operator-actionable guidance.
"""
# Canonical kind values. Listed for reference / IDE auto-completion;
# presence in this set is NOT validated at construction time so callers
# can extend if needed.
KINDS = frozenset({
'pem_not_found',
'pem_parse',
'certutil_not_found',
'certutil_call',
'cert_not_found',
'marker_write',
'classify',
'store_not_writable',
'fips',
'concurrent_install',
'budget_exceeded',
'state_fs',
})
def __init__(self, kind: str, message: str) -> None:
"""Construct a CaOverrideError.
Args:
kind: Canonical kind string (see ``KINDS``).
message: Human-readable diagnostic for the operator.
"""
super().__init__(message)
self.kind = kind
self.message = message
def __repr__(self) -> str:
return 'CaOverrideError(kind=%r, message=%r)' % (self.kind, self.message)
# Kinds that are TRANSIENT / BENIGN at process startup: the override CA is (or
# will be) installed by a peer process or on a later run, so a cfn-* tool must
# NOT hard-exit on them -- it should log and continue. Everything else means the
# pinned trust genuinely could not be established (corrupt PEM, real store
# failure, FIPS-disallowed sig, ...) and IS fatal (fail loud, exit 1).
# - concurrent_install: another cfn process holds the install lock and is
# doing the install; the loser waited out the lock. The cert DOES get
# installed by the winner. Common on first boot (cfn-init + cfn-hup race).
# - budget_exceeded: a self-imposed per-run retry/time budget tripped -- a
# transient throttle, not a trust failure.
# - marker_write: the certs installed fine but the bookkeeping marker file
# could not be written; annoying (rotation/uninstall bookkeeping) but trust
# is intact for this boot.
BENIGN_INSTALL_KINDS = frozenset({
'concurrent_install',
'budget_exceeded',
'marker_write',
})
def is_benign_install_failure(exc: Exception) -> bool:
"""True if ``exc`` is a CaOverrideError whose ``.kind`` is transient/benign
(see :data:`BENIGN_INSTALL_KINDS`) and should be logged-and-tolerated rather
than turned into a hard process exit. Pure predicate: no ssl, no I/O."""
return getattr(exc, 'kind', None) in BENIGN_INSTALL_KINDS
def format_install_tolerated(exc: Exception) -> str:
"""Log line for a BENIGN install failure the tool is deliberately tolerating
(as opposed to :func:`format_install_failure`, which is the loud fatal
line). Pure string formatting: no ssl, no I/O."""
kind = getattr(exc, 'kind', 'unknown')
return (
'%s override CA install did not complete (kind=%s): %s'
' -- transient/benign, continuing (a peer process or later run will'
' complete it)' % (_LOG_PREFIX, kind, exc)
)
def format_install_failure(exc: Exception) -> str:
"""Return the single, uniform 'override CA install FAILED' log line.
Shared by every cfn-* entrypoint (and cfnbootstrap.winhup) so the loud
failure message is byte-identical across all callers. Pure string
formatting: imports NO ``ssl`` and performs NO I/O.
Args:
exc: The exception that aborted the override-CA install. When it is a
:class:`CaOverrideError` its ``.kind`` is surfaced; otherwise the
kind is reported as ``'unknown'``.
Returns:
A greppable, operator-actionable single-line string prefixed with
``[CaOverrideInstall]``.
"""
kind = getattr(exc, 'kind', 'unknown')
return (
'%s override CA install FAILED (kind=%s): %s'
' -- refusing to continue with system-store-only trust'
% (_LOG_PREFIX, kind, exc)
)
def _resolve_override_pem_path() -> str:
"""Return the configured override-PEM path WITHOUT validating existence.
Honours the pre-existing ``CA_OVERRIDE`` env var via
:func:`cfnbootstrap.http._certs._override_path`. No new env var is
introduced for the source-PEM path.
"""
# Local import keeps the OS-dispatcher importable from contexts where the
# http subpackage may not be initialised (e.g. extremely early bootstrap
# logging setup).
from cfnbootstrap.http import _certs
return _certs._override_path()
def ensure_ca_override_installed() -> None:
"""Ensure the override CA(s) at the platform PEM path are trusted by the OS.
Safe and cheap to call from every cfn-* entrypoint at process startup.
No-op when no override PEM is present (commercial path). Idempotent: when
the on-disk marker records the current PEM hash, returns in O(1) without
invoking certutil.
Raises:
CaOverrideError: on any hard failure (PEM corrupt, certutil missing
or failed, marker unwritable, FIPS refusal, concurrent-install
lock contention, wall-clock budget exhaustion). cfn-* entrypoints
MUST NOT catch this error.
Returns:
None. The function is intended for its side effect of populating the
Windows cert stores (Root / CA) on os.name == 'nt'. On Linux it is a
documented no-op.
"""
log.debug('%s ensure_ca_override_installed called', _LOG_PREFIX)
# Step 1: resolve source PEM path. The pre-existing
# CA_OVERRIDE env var is honoured by _certs._override_path(); no new env
# var is introduced here.
pem_path = _resolve_override_pem_path()
# Step 2: PEM-absence short-circuit. Commercial hosts have no override PEM,
# so they return here before any install work. Preserves the byte-for-byte
# commercial Windows path.
if not pem_path or not os.path.isfile(pem_path):
log.debug(
'%s no override PEM at %s; nothing to install',
_LOG_PREFIX, pem_path,
)
return
if os.name == 'nt':
_dispatch_windows(pem_path)
else:
_dispatch_posix(pem_path)
def _dispatch_posix(pem_path: str) -> None:
"""Linux dispatch path.
The existing :func:`cfnbootstrap.http._certs.resolve_ca_bundle` already
returns the override PEM path directly to the stdlib ``ssl`` module via
:mod:`cfnbootstrap.http._backend_posix`, so trust is enforced at request
time without any install step. This function is a documented no-op that
exists so the wiring in the cfn-* entrypoints is identical across
platforms.
"""
log.debug(
'%s POSIX dispatch: override PEM at %s will be honoured at request '
'time by the stdlib ssl module; no install step needed',
_LOG_PREFIX, pem_path,
)
def _dispatch_windows(pem_path: str) -> None:
"""Windows dispatch path.
Delegates to :mod:`cfnbootstrap._ca_install_win`. The Windows module
handles PEM hashing, marker fast-path, concurrent-install lock,
classify-via-certutil-dump, addstore-with-probe, and rotation.
Raises:
CaOverrideError: propagated unchanged from the Windows module.
"""
# Local import keeps the import graph clean on Linux (where the Windows
# module is never imported) and avoids tripping any future Windows-only
# import-time side effects in unit-test discovery on a Linux build host.
from cfnbootstrap import _ca_install_win
marker_path = os.environ.get(
'CFN_CA_OVERRIDE_MARKER_PATH',
os.path.expandvars(r'${SystemDrive}\cfn\state\ca-install-marker.json'),
)
_ca_install_win.install_or_rotate(pem_path=pem_path, marker_path=marker_path)
# Optional helper exposed for diagnostic tooling. Not part of the documented
# public surface used by the cfn-* entrypoints.
def _override_pem_path_for_diagnostics() -> Optional[str]:
"""Return the resolved override-PEM path or None if unconfigured.
Used by diagnostic / status tools; not used by the install hot path.
"""
try:
path = _resolve_override_pem_path()
except Exception: # pragma: no cover -- diagnostic-only
return None
return path or None