Description
SUMMARY
k8s_cp nor k8s_exec cannot work with http proxy authentication.
both can work only when http proxy need no authentiation.
I tested most patterns for http proxy auth as described in docs/kubernetes.core.k8s_xxx_module.rst
- environment variables : K8S_AUTH_PROXY_HEADERS_BASIC_AUTH and K8S_AUTH_PROXY_HEADERS_PROXY_BASIC_AUTH
- specifing proxy_headers block with basic_auth and proxy_basic_auth
but always it fails by following message.
deloying pod with kubernetes.core.k8s via http proxy authentication works.
task path: /mnt/k8s.yaml:38
redirecting (type: action) kubernetes.core.k8s_exec to kubernetes.core.k8s_info
redirecting (type: action) kubernetes.core.k8s_exec to kubernetes.core.k8s_info
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: root
<127.0.0.1> EXEC /bin/sh -c 'echo ~root && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1632388824.0367606-6684-265204369558111 `" && echo ansible-tmp-1632388824.0367606-6684-265204369558111="` echo /root/.ansible/tmp/ansible-tmp-1632388824.0367606-6684-265204369558111 `" ) && sleep 0'
Loading collection cloud.common from /root/.ansible/collections/ansible_collections/cloud/common
Using module file /root/.ansible/collections/ansible_collections/kubernetes/core/plugins/modules/k8s_exec.py
<127.0.0.1> PUT /root/.ansible/tmp/ansible-local-6492mx8edj7e/tmpp1r4bfl7 TO /root/.ansible/tmp/ansible-tmp-1632388824.0367606-6684-265204369558111/AnsiballZ_k8s_exec.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1632388824.0367606-6684-265204369558111/ /root/.ansible/tmp/ansible-tmp-1632388824.0367606-6684-265204369558111/AnsiballZ_k8s_exec.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'python /root/.ansible/tmp/ansible-tmp-1632388824.0367606-6684-265204369558111/AnsiballZ_k8s_exec.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1632388824.0367606-6684-265204369558111/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
File "/tmp/ansible_kubernetes.core.k8s_exec_payload_tngkyn7y/ansible_kubernetes.core.k8s_exec_payload.zip/ansible_collections/kubernetes/core/plugins/modules/k8s_exec.py", line 159, in execute_module
File "/usr/local/lib/python3.9/dist-packages/kubernetes/stream/stream.py", line 35, in _websocket_request
return api_method(*args, **kwargs)
File "/usr/local/lib/python3.9/dist-packages/kubernetes/client/api/core_v1_api.py", line 994, in connect_get_namespaced_pod_exec
return self.connect_get_namespaced_pod_exec_with_http_info(name, namespace, **kwargs) # noqa: E501
File "/usr/local/lib/python3.9/dist-packages/kubernetes/client/api/core_v1_api.py", line 1101, in connect_get_namespaced_pod_exec_with_http_info
return self.api_client.call_api(
File "/usr/local/lib/python3.9/dist-packages/kubernetes/client/api_client.py", line 348, in call_api
return self.__call_api(resource_path, method,
File "/usr/local/lib/python3.9/dist-packages/kubernetes/client/api_client.py", line 180, in __call_api
response_data = self.request(
File "/usr/local/lib/python3.9/dist-packages/kubernetes/stream/ws_client.py", line 474, in websocket_call
raise ApiException(status=0, reason=str(e))
fatal: [localhost]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"api_key": null,
"ca_cert": null,
"client_cert": null,
"client_key": null,
"command": "/bin/sh -c 'rm -f /tmp/debian-bullseye.txt\ndate > /tmp/debian-bullseye.txt\n'",
"container": "debian-bullseye",
"context": null,
"host": null,
"kubeconfig": "/root/.kube/config",
"namespace": "default",
"password": null,
"persist_config": null,
"pod": "sample-0",
"proxy": "http://basicauth.proxy.local:8080",
"proxy_headers": {
"basic_auth": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"proxy_basic_auth": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"user_agent": null
},
"username": null,
"validate_certs": null
}
},
"msg": "Failed to execute on pod sample-0 due to : (0)\nReason: failed CONNECT via proxy status: 407\n"
ISSUE TYPE
- Bug Report
COMPONENT NAME
- k8s_cp
- k8s_exec
- ... (not sure)
ANSIBLE VERSION
ansible [core 2.11.5]
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.9/dist-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110]
jinja version = 3.0.1
libyaml = True
COLLECTION VERSION
# /root/.ansible/collections/ansible_collections
Collection Version
--------------- -------
cloud.common 2.0.4
kubernetes.core 2.2.0
# pip list
kubernetes 18.20.0
CONFIGURATION
(empty)
OS / ENVIRONMENT
debian 11 (bullseye)
STEPS TO REPRODUCE
- setup http proxy server requiring basic authentication.
- deploy pod from behind http proxy (any official image is ok)
- k8s_exec (command: 'date') or k8s_cp (upload or download text file) from behind above http proxy.
Following are my test codes.
ansible-playbook -i hosts -e test=alpine:latest
- name: bootstrap ansible test
hosts: localhost
gather_facts: no
connection: local
tasks:
- ...
---
- name: setup
block:
- set_fact:
images: [ "alpine:latest", "debian:bullseye" ]
kubeconfig: "/root/.kube/config"
cases: "{{ [] }}"
- set_fact:
cases: |
{{ cases + [{ 'image': item , 'container': item|replace(':','-')|replace('/','-')|replace('.','') }] }}
with_items: "{{ images }}"
- template:
src: "pod-template.j2"
dest: "/tmp/pod-sample.yaml"
- k8s:
state: present
src: "/tmp/pod-sample.yaml"
kubeconfig: "{{ kubeconfig }}"
- name: wait pod ready (this doesn't work in some cases...)
command: |
kubectl wait pod --for=condition=ready --kubeconfig {{kubeconfig}} sample-0 --timeout=150s
- name: prepare content
copy:
dest: "/tmp/{{item}}.sh"
content: |
#!/bin/sh
echo "{{item}}" > /tmp/{{item}}.txt
date >> /tmp/{{item}}.txt
mode: +x
with_items: "{{ cases | map(attribute='container')| list }}"
- name: "test : {{ test }}"
set_fact:
target: "{{ test |replace(':','-')|replace('/','-')| replace('.','') }}"
- name: test {{ target }}
block:
- include_tasks: "k8s.yaml"
vars:
container: "{{ target }}"
namespace: "default"
pod: "sample-0"
shell: "/bin/sh -c"
exec: |
rm -f /tmp/{{target}}.txt
date > /tmp/{{target}}.txt
download: { 'remote_path': "/tmp/{{target}}.txt", 'local_path': "/tmp/{{target}}1.txt" }
- include_tasks: "k8s.yaml"
vars:
container: "{{ target }}"
namespace: "default"
pod: "sample-0"
shell: "/bin/sh -c"
upload: { 'local_path': "/tmp/{{target}}.sh", 'remote_path':"/tmp/{{target}}1.sh" }
exec: |
rm -f /tmp/{{target}}.txt
/tmp/{{target}}1.sh
download: { 'remote_path': "/tmp/{{target}}.txt", 'local_path': "/tmp/{{target}}1.txt" }
- debug:
msg: "got: {{ lookup('file', '/tmp/{{target}}1.txt') }}"
---
# k8s.yaml
- name: get environment variables from current shell for proxy
set_fact:
localenv: "{{ localenv|default({}) | combine ({ item : (lookup('env', item)| default('')) }) }}"
with_items:
- https_proxy
- no_proxy
- K8S_AUTH_PROXY
- K8S_AUTH_PROXY_HEADERS_BASIC_AUTH
- K8S_AUTH_PROXY_HEADERS_PROXY_BASIC_AUTH
- debug:
var: localenv
- name: "uploading x core.k8s_cp"
when: upload is defined
kubernetes.core.k8s_cp:
state: to_pod
kubeconfig: "{{ kubeconfig }}"
namespace: "{{ namespace }}"
pod: "{{ pod }}"
container: "{{ container }}"
local_path: "{{ upload.local_path }}"
remote_path: "{{ upload.remote_path }}"
proxy: "{{ localenv.K8S_AUTH_PROXY }}"
proxy_headers:
basic_auth: "{{ localenv.K8S_AUTH_PROXY_HEADERS_BASIC_AUTH }}"
proxy_basic_auth: "{{ localenv.K8S_AUTH_PROXY_HEADERS_PROXY_BASIC_AUTH }}"
- name: "exec x core.k8s_exec"
when: exec is defined
kubernetes.core.k8s_exec:
kubeconfig: "{{ kubeconfig }}"
namespace: "{{ namespace }}"
pod: "{{ pod }}"
container: "{{ container }}"
command: >-
{{shell}} '{{ exec }}'
proxy: "{{ localenv.K8S_AUTH_PROXY }}"
proxy_headers:
basic_auth: "{{ localenv.K8S_AUTH_PROXY_HEADERS_BASIC_AUTH }}"
proxy_basic_auth: "{{ localenv.K8S_AUTH_PROXY_HEADERS_PROXY_BASIC_AUTH }}"
register: result
- name: "result of remote exection"
debug:
var: result
- name: "downloading x core.k8s_cp"
when: download is defined
kubernetes.core.k8s_cp:
state: from_pod
kubeconfig: "{{ kubeconfig }}"
namespace: "{{ namespace }}"
pod: "{{ pod }}"
container: "{{ container }}"
remote_path: "{{ download.remote_path }}"
local_path: "{{ download.local_path }}"
proxy: "{{ localenv.K8S_AUTH_PROXY }}"
proxy_headers:
basic_auth: "{{ localenv.K8S_AUTH_PROXY_HEADERS_BASIC_AUTH }}"
proxy_basic_auth: "{{ localenv.K8S_AUTH_PROXY_HEADERS_PROXY_BASIC_AUTH }}"
---
# pod-template.j2
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: "sample"
namespace: "default"
spec:
selector:
matchLabels:
k8s-app: "sample"
serviceName: "sample"
replicas: 1
template:
metadata:
labels:
k8s-app: "sample"
spec:
containers:
{% for node in cases %}
- name: {{ node.container }}
image: {{ node.image }}
imagePullPolicy: IfNotPresent
command:
- sh
- "-c"
- |
tail -f /dev/null
{% endfor %}
EXPECTED RESULTS
as it described in docs, both of k8s_cp and k8s_exec can work with http proxy authentication.
ACTUAL RESULTS
both k8s_cp and k8s_exec failed when http proxy requires authentication.