diff --git a/contents/common.py b/contents/common.py index ad98af3..46d3e2e 100644 --- a/contents/common.py +++ b/contents/common.py @@ -1,4 +1,5 @@ import re +import os def check_is_file(destination): @@ -64,3 +65,29 @@ def conditionalReplace( aMatch ) : result = '"' + result + '"' return result+' ' + + +def configure_proxy(arguments, winrmproxy, winrmnoproxy, endpoint, log): + from requests.utils import should_bypass_proxies + + if winrmproxy: + if winrmnoproxy: + # Delegate to requests via env vars so NO_PROXY matching works + os.environ['HTTP_PROXY'] = winrmproxy + os.environ['HTTPS_PROXY'] = winrmproxy + os.environ['NO_PROXY'] = winrmnoproxy + log.debug("Proxy via env vars: HTTP(S)_PROXY=%s, NO_PROXY=%s" % (winrmproxy, winrmnoproxy)) + + if should_bypass_proxies(endpoint, no_proxy=winrmnoproxy): + log.info("Connecting to %s DIRECTLY (matched NO_PROXY: %s)" % (endpoint, winrmnoproxy)) + else: + log.info("Connecting to %s via PROXY (%s)" % (endpoint, winrmproxy)) + else: + # Legacy: explicit proxy for all connections + arguments["proxy"] = winrmproxy + log.info("Connecting to %s via PROXY (%s)" % (endpoint, winrmproxy)) + else: + if winrmnoproxy: + log.warning("noproxy is set but no proxy configured; noproxy ignored") + log.info("Connecting to %s DIRECTLY (no proxy configured)" % endpoint) + return arguments diff --git a/contents/winrm-check.py b/contents/winrm-check.py index 70a97a3..ba53b19 100644 --- a/contents/winrm-check.py +++ b/contents/winrm-check.py @@ -9,6 +9,7 @@ import colored_formatter from colored_formatter import ColoredFormatter import kerberosauth +import common #checking and importing dependencies @@ -105,6 +106,8 @@ parser.add_argument('--debug', help='debug',default="False") parser.add_argument('--certpath', help='certpath') parser.add_argument('--krb5config', help='krb5config',default="/etc/krb5.conf") +parser.add_argument('--proxy', help='proxy', default=None) +parser.add_argument('--noproxy', help='noproxy patterns', default=None) args = parser.parse_args() @@ -161,6 +164,13 @@ if args.certpath: certpath = args.certpath +winrmproxy = None +winrmnoproxy = None +if args.proxy and args.proxy not in ("None", ""): + winrmproxy = args.proxy +if args.noproxy and args.noproxy not in ("None", ""): + winrmnoproxy = args.noproxy + if not hostname: print("hostname is required") sys.exit(1) @@ -243,6 +253,8 @@ arguments["credssp_disable_tlsv1_2"] = diabletls12 +common.configure_proxy(arguments, winrmproxy, winrmnoproxy, endpoint, log) + if authentication == "kerberos": k5bConfig = kerberosauth.KerberosAuth(krb5config=krb5config, log=log, kinit_command=kinit,username=username, password=password) k5bConfig.get_ticket() diff --git a/contents/winrm-exec.py b/contents/winrm-exec.py index a70de9f..7eb3fe6 100755 --- a/contents/winrm-exec.py +++ b/contents/winrm-exec.py @@ -139,6 +139,7 @@ def httpclient_log(*args): retryconnectiondelay = 0 username = None winrmproxy = None +winrmnoproxy = None if "RD_CONFIG_AUTHTYPE" in os.environ: authentication = os.getenv("RD_CONFIG_AUTHTYPE") @@ -189,6 +190,10 @@ def httpclient_log(*args): winrmproxy = os.getenv("RD_CONFIG_WINRMPROXY") log.debug("winrmproxy: " + str(winrmproxy)) +if "RD_CONFIG_WINRMNOPROXY" in os.environ: + winrmnoproxy = os.getenv("RD_CONFIG_WINRMNOPROXY") + log.debug("winrmnoproxy: " + str(winrmnoproxy)) + if "RD_CONFIG_ENABLEDHTTPDEBUG" in os.environ: if os.getenv("RD_CONFIG_ENABLEDHTTPDEBUG") == "true": enabledHttpDebug = True @@ -311,8 +316,7 @@ def httpclient_log(*args): if(readtimeout): arguments["read_timeout_sec"] = readtimeout -if(winrmproxy): - arguments["proxy"] = winrmproxy +common.configure_proxy(arguments, winrmproxy, winrmnoproxy, endpoint, log) if(operationtimeout): arguments["operation_timeout_sec"] = operationtimeout diff --git a/contents/winrm-filecopier.py b/contents/winrm-filecopier.py index 784fe73..50c3802 100644 --- a/contents/winrm-filecopier.py +++ b/contents/winrm-filecopier.py @@ -268,6 +268,7 @@ def winrm_upload(self, certpath = None username = None winrmproxy = None +winrmnoproxy = None if os.environ.get('RD_CONFIG_OVERRIDE') == 'true': override = True @@ -299,6 +300,9 @@ def winrm_upload(self, if "RD_CONFIG_WINRMPROXY" in os.environ: winrmproxy = os.getenv("RD_CONFIG_WINRMPROXY") +if "RD_CONFIG_WINRMNOPROXY" in os.environ: + winrmnoproxy = os.getenv("RD_CONFIG_WINRMNOPROXY") + if "RD_OPTION_USERNAME" in os.environ and os.getenv("RD_OPTION_USERNAME"): #take user from job username = os.getenv("RD_OPTION_USERNAME").strip('\'') @@ -367,8 +371,7 @@ def winrm_upload(self, arguments["credssp_disable_tlsv1_2"] = diabletls12 -if(winrmproxy): - arguments["proxy"] = winrmproxy +common.configure_proxy(arguments, winrmproxy, winrmnoproxy, endpoint, log) if(readtimeout): arguments["read_timeout_sec"] = readtimeout diff --git a/plugin.yaml b/plugin.yaml index d2f5334..f8292bb 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -110,6 +110,15 @@ providers: renderingOptions: groupName: Connection instance-scope-node-attribute: "winrm-proxy" + - name: winrmnoproxy + title: No Proxy List + description: "Comma-separated list of hosts/IPs/CIDRs that bypass the proxy. Supports exact IPs, CIDR notation (192.168.1.0/24), domain suffixes (.internal.corp), and wildcard (*). Requires Proxy to also be set. It can be overwriting at node level using `winrm-noproxy`" + type: String + required: false + scope: Instance + renderingOptions: + groupName: Connection + instance-scope-node-attribute: "winrm-noproxy" - name: operationtimeout title: operation timeout description: "maximum allowed time in seconds for any single wsman HTTP operation (default 20). Note that operation timeouts while receiving output (the only wsman operation that should take any significant time, and where these timeouts are expected) will be silently retried indefinitely. It can be overwriting at node level using `winrm-operationtimeout`" @@ -380,6 +389,15 @@ providers: renderingOptions: groupName: Connection instance-scope-node-attribute: "winrm-proxy" + - name: winrmnoproxy + title: No Proxy List + description: "Comma-separated list of hosts/IPs/CIDRs that bypass the proxy. Supports exact IPs, CIDR notation (192.168.1.0/24), domain suffixes (.internal.corp), and wildcard (*). Requires Proxy to also be set. It can be overwriting at node level using `winrm-noproxy`" + type: String + required: false + scope: Instance + renderingOptions: + groupName: Connection + instance-scope-node-attribute: "winrm-noproxy" - name: enabledhttpdebug title: Enable HTTP logging in debug mode description: "Print extra http logging in debug mode" @@ -417,7 +435,7 @@ providers: plugin-type: script script-interpreter: ${config.interpreter} -u script-file: winrm-check.py - script-args: --username ${config.username} --hostname ${config.hostname} --password ${config.password_storage_path} --authentication ${config.authtype} --transport ${config.winrmtransport} --port ${config.winrmport} --nossl ${config.nossl} --debug ${config.debug} --certpath ${config.certpath} + script-args: --username ${config.username} --hostname ${config.hostname} --password ${config.password_storage_path} --authentication ${config.authtype} --transport ${config.winrmtransport} --port ${config.winrmport} --nossl ${config.nossl} --debug ${config.debug} --certpath ${config.certpath} --proxy ${config.winrmproxy} --noproxy ${config.winrmnoproxy} config: - name: interpreter title: Python Interpreter @@ -512,4 +530,14 @@ providers: default: "false" required: false renderingOptions: - groupName: Kerberos \ No newline at end of file + groupName: Kerberos + - name: winrmproxy + title: Proxy + description: "Specify a proxy address for communicating with Windows nodes. Example HTTP proxy strings are http://server:port and http://user:pass@server:port. An example SOCKS5 proxy string is socks5://user:pass@server:port." + type: String + required: false + - name: winrmnoproxy + title: No Proxy List + description: "Comma-separated list of hosts/IPs/CIDRs that bypass the proxy. Supports exact IPs, CIDR notation (192.168.1.0/24), domain suffixes (.internal.corp), and wildcard (*)." + type: String + required: false \ No newline at end of file