mirror of
https://github.com/ansible-collections/kubernetes.core.git
synced 2026-05-06 21:12:37 +00:00
This is a backport of PR #1014 as merged into main (4fa3648).
SUMMARY
Resolves #782
ISSUE TYPE
Bugfix Pull Request
ADDITIONAL INFORMATION
The proper redaction of kubeconfig data can be seen by running this example playbook with verbosity of -vvv against the code in this PR.
Prior to these changes, all info was redacted (as shown in the example below):
ok: [local] => {
"changed": false,
"invocation": {
"module_args": {
"api_key": null,
"binary_path": null,
"ca_cert": null,
"context": null,
"get_all_values": false,
"host": null,
"kubeconfig": {
"apiVersion": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"clusters": [
{
"cluster": {
"insecure-skip-tls-verify": true,
"server": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
"name": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
{
"cluster": {
"certificate-authority-data": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"server": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
"name": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
{
"cluster": {
"certificate-authority": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"extensions": [
{
"extension": {
"last-update": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"provider": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"version": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
"name": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
}
],
"server": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
"name": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
}
],
"contexts": [
{
"context": {
"cluster": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"user": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
"name": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
{
"context": {
"cluster": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"user": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
"name": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
},
[output shortened]
With the changes in this PR, only sensitive data is redacted:
ok: [local] => {
"changed": false,
"invocation": {
"module_args": {
"api_key": null,
"binary_path": null,
"ca_cert": null,
"context": null,
"get_all_values": false,
"host": null,
"kubeconfig": {
"apiVersion": "v1",
"clusters": [
{
"cluster": {
"insecure-skip-tls-verify": true,
"server": "<server address>"
},
"name": "exercise"
},
{
"cluster": {
"certificate-authority-data": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"server": "<server address>"
},
"name": "kind-drain-test"
},
{
"cluster": {
"certificate-authority": "<path to .crt>",
"extensions": [
{
"extension": {
"last-update": "Tue, 07 Oct 2025 11:25:54 EDT",
"provider": "minikube.sigs.k8s.io",
"version": "v1.35.0"
},
"name": "cluster_info"
}
],
"server": "<server address>"
},
"name": "minikube"
}
],
"contexts": [
{
"context": {
"cluster": "exercise-pod",
"user": "bianca"
},
"name": "exercise"
},
{
"context": {
"cluster": "kind-drain-test",
"user": "kind-drain-test"
},
"name": "kind-drain-test"
},
[output shortened]
Reviewed-by: GomathiselviS <gomathiselvi@gmail.com>
This commit is contained in:
@@ -2,6 +2,8 @@ from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
import warnings
|
||||
|
||||
|
||||
def list_dict_str(value):
|
||||
if isinstance(value, (list, dict, str)):
|
||||
@@ -9,6 +11,54 @@ def list_dict_str(value):
|
||||
raise TypeError
|
||||
|
||||
|
||||
def extract_sensitive_values_from_kubeconfig(kubeconfig_data):
|
||||
"""
|
||||
Extract only sensitive string values from kubeconfig data for no_log_values.
|
||||
|
||||
:arg kubeconfig_data: Dictionary containing kubeconfig data
|
||||
:returns: Set of sensitive string values to be added to no_log_values
|
||||
"""
|
||||
values = set()
|
||||
sensitive_fields = {
|
||||
"token",
|
||||
"password",
|
||||
"secret",
|
||||
"client-key-data",
|
||||
"client-certificate-data",
|
||||
"certificate-authority-data",
|
||||
"api_key",
|
||||
"access-token",
|
||||
"refresh-token",
|
||||
}
|
||||
|
||||
# Check API version and warn if not v1
|
||||
if isinstance(kubeconfig_data, dict):
|
||||
api_version = kubeconfig_data.get("apiVersion", "v1")
|
||||
if api_version != "v1":
|
||||
warnings.warn(
|
||||
f"Kubeconfig API version '{api_version}' is not 'v1'. "
|
||||
f"Sensitive field redaction is only guaranteed for API version 'v1'. "
|
||||
f"Some sensitive data may not be properly redacted from the logs.",
|
||||
UserWarning,
|
||||
)
|
||||
|
||||
def _extract_recursive(data, current_path=""):
|
||||
if isinstance(data, dict):
|
||||
for key, value in data.items():
|
||||
path = f"{current_path}.{key}" if current_path else key
|
||||
if key in sensitive_fields:
|
||||
if isinstance(value, str):
|
||||
values.add(value)
|
||||
else:
|
||||
_extract_recursive(value, path)
|
||||
elif isinstance(data, list):
|
||||
for i, item in enumerate(data):
|
||||
_extract_recursive(item, f"{current_path}[{i}]")
|
||||
|
||||
_extract_recursive(kubeconfig_data)
|
||||
return values
|
||||
|
||||
|
||||
AUTH_PROXY_HEADERS_SPEC = dict(
|
||||
proxy_basic_auth=dict(type="str", no_log=True),
|
||||
basic_auth=dict(type="str", no_log=True),
|
||||
@@ -16,7 +66,7 @@ AUTH_PROXY_HEADERS_SPEC = dict(
|
||||
)
|
||||
|
||||
AUTH_ARG_SPEC = {
|
||||
"kubeconfig": {"type": "raw", "no_log": True},
|
||||
"kubeconfig": {"type": "raw"},
|
||||
"context": {},
|
||||
"host": {},
|
||||
"api_key": {"no_log": True},
|
||||
|
||||
@@ -15,6 +15,9 @@ import tempfile
|
||||
import traceback
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
extract_sensitive_values_from_kubeconfig,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.version import (
|
||||
LooseVersion,
|
||||
)
|
||||
@@ -118,6 +121,13 @@ class AnsibleHelmModule(object):
|
||||
elif isinstance(kubeconfig, dict):
|
||||
kubeconfig_content = kubeconfig
|
||||
|
||||
# Redact sensitive fields from kubeconfig for logging purposes
|
||||
if kubeconfig_content:
|
||||
# Add original sensitive values to no_log_values to prevent them from appearing in logs
|
||||
self._module.no_log_values.update(
|
||||
extract_sensitive_values_from_kubeconfig(kubeconfig_content)
|
||||
)
|
||||
|
||||
if self.params.get("ca_cert"):
|
||||
ca_cert = self.params.get("ca_cert")
|
||||
if LooseVersion(self.get_helm_version()) < LooseVersion("3.5.0"):
|
||||
|
||||
@@ -16,7 +16,6 @@ HELM_AUTH_ARG_SPEC = dict(
|
||||
type="raw",
|
||||
aliases=["kubeconfig_path"],
|
||||
fallback=(env_fallback, ["K8S_AUTH_KUBECONFIG"]),
|
||||
no_log=True,
|
||||
),
|
||||
host=dict(type="str", fallback=(env_fallback, ["K8S_AUTH_HOST"])),
|
||||
ca_cert=dict(
|
||||
|
||||
@@ -3,6 +3,9 @@ from typing import Optional
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.converters import to_text
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.args_common import (
|
||||
extract_sensitive_values_from_kubeconfig,
|
||||
)
|
||||
from ansible_collections.kubernetes.core.plugins.module_utils.version import (
|
||||
LooseVersion,
|
||||
)
|
||||
@@ -33,6 +36,15 @@ class AnsibleK8SModule:
|
||||
|
||||
self._module = self.settings["module_class"](**kwargs)
|
||||
|
||||
# Apply kubeconfig redaction for logging purposes
|
||||
if hasattr(self._module, "params") and hasattr(self._module, "no_log_values"):
|
||||
kubeconfig = self._module.params.get("kubeconfig")
|
||||
if kubeconfig and isinstance(kubeconfig, dict):
|
||||
# Add sensitive values to no_log_values to prevent them from appearing in logs
|
||||
self._module.no_log_values.update(
|
||||
extract_sensitive_values_from_kubeconfig(kubeconfig)
|
||||
)
|
||||
|
||||
if self.settings["check_k8s"]:
|
||||
self.requires("kubernetes")
|
||||
self.has_at_least("kubernetes", "24.2.0", warn=True)
|
||||
|
||||
Reference in New Issue
Block a user