Skip to content

Commit acc07d7

Browse files
committed
incluster_config loader should fail on empty host/port or cert/token file
1 parent 66e4f5f commit acc07d7

File tree

2 files changed

+67
-42
lines changed

2 files changed

+67
-42
lines changed

kubernetes/config/incluster_config.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818

1919
from .config_exception import ConfigException
2020

21-
_SERVICE_HOST_ENV_NAME = "KUBERNETES_SERVICE_HOST"
22-
_SERVICE_PORT_ENV_NAME = "KUBERNETES_SERVICE_PORT"
23-
_SERVICE_TOKEN_FILENAME = "/var/run/secrets/kubernetes.io/serviceaccount/token"
24-
_SERVICE_CERT_FILENAME = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
21+
SERVICE_HOST_ENV_NAME = "KUBERNETES_SERVICE_HOST"
22+
SERVICE_PORT_ENV_NAME = "KUBERNETES_SERVICE_PORT"
23+
SERVICE_TOKEN_FILENAME = "/var/run/secrets/kubernetes.io/serviceaccount/token"
24+
SERVICE_CERT_FILENAME = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
2525

2626

2727
def _join_host_port(host, port):
@@ -35,10 +35,8 @@ def _join_host_port(host, port):
3535

3636
class InClusterConfigLoader(object):
3737

38-
def __init__(self, host_env_name, port_env_name, token_filename,
38+
def __init__(self, token_filename,
3939
cert_filename, environ=os.environ):
40-
self._host_env_name = host_env_name
41-
self._port_env_name = port_env_name
4240
self._token_filename = token_filename
4341
self._cert_filename = cert_filename
4442
self._environ = environ
@@ -48,24 +46,34 @@ def load_and_set(self):
4846
self._set_config()
4947

5048
def _load_config(self):
51-
if (self._host_env_name not in self._environ or
52-
self._port_env_name not in self._environ):
49+
if (SERVICE_HOST_ENV_NAME not in self._environ or
50+
SERVICE_PORT_ENV_NAME not in self._environ):
5351
raise ConfigException("Service host/port is not set.")
5452

53+
if (not self._environ[SERVICE_HOST_ENV_NAME] or
54+
not self._environ[SERVICE_PORT_ENV_NAME]):
55+
raise ConfigException("Service host/port is set but empty.")
56+
5557
self.host = (
56-
"https://" + _join_host_port(self._environ[self._host_env_name],
57-
self._environ[self._port_env_name]))
58+
"https://" + _join_host_port(self._environ[SERVICE_HOST_ENV_NAME],
59+
self._environ[SERVICE_PORT_ENV_NAME]))
5860

5961
if not os.path.isfile(self._token_filename):
6062
raise ConfigException("Service token file does not exists.")
6163

6264
with open(self._token_filename) as f:
6365
self.token = f.read()
66+
if not self.token:
67+
raise ConfigException("Token file exists but empty.")
6468

6569
if not os.path.isfile(self._cert_filename):
6670
raise ConfigException(
6771
"Service certification file does not exists.")
6872

73+
with open(self._cert_filename) as f:
74+
if not f.read():
75+
raise ConfigException("Cert file exists but empty.")
76+
6977
self.ssl_ca_cert = self._cert_filename
7078

7179
def _set_config(self):
@@ -79,7 +87,5 @@ def load_incluster_config():
7987
cluster. It's intended for clients that expect to be running inside a pod
8088
running on kubernetes. It will raise an exception if called from a process
8189
not running in a kubernetes environment."""
82-
InClusterConfigLoader(host_env_name=_SERVICE_HOST_ENV_NAME,
83-
port_env_name=_SERVICE_PORT_ENV_NAME,
84-
token_filename=_SERVICE_TOKEN_FILENAME,
85-
cert_filename=_SERVICE_CERT_FILENAME).load_and_set()
90+
InClusterConfigLoader(token_filename=SERVICE_TOKEN_FILENAME,
91+
cert_filename=SERVICE_CERT_FILENAME).load_and_set()

kubernetes/config/incluster_config_test.py

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,21 @@
1717
import unittest
1818

1919
from .config_exception import ConfigException
20-
from .incluster_config import (_SERVICE_HOST_ENV_NAME, _SERVICE_PORT_ENV_NAME,
21-
InClusterConfigLoader)
20+
from .incluster_config import (SERVICE_HOST_ENV_NAME, SERVICE_PORT_ENV_NAME,
21+
InClusterConfigLoader, _join_host_port)
2222

2323
_TEST_TOKEN = "temp_token"
24+
_TEST_CERT = "temp_cert"
2425
_TEST_HOST = "127.0.0.1"
25-
_TEST_IPV6_HOST = "::1"
2626
_TEST_PORT = "80"
27-
_TEST_ENVIRON = {_SERVICE_HOST_ENV_NAME: _TEST_HOST,
28-
_SERVICE_PORT_ENV_NAME: _TEST_PORT}
29-
_TEST_IPV6_ENVIRON = {_SERVICE_HOST_ENV_NAME: _TEST_IPV6_HOST,
30-
_SERVICE_PORT_ENV_NAME: _TEST_PORT}
27+
_TEST_HOST_PORT = "127.0.0.1:80"
28+
_TEST_IPV6_HOST = "::1"
29+
_TEST_IPV6_HOST_PORT = "[::1]:80"
30+
31+
_TEST_ENVIRON = {SERVICE_HOST_ENV_NAME: _TEST_HOST,
32+
SERVICE_PORT_ENV_NAME: _TEST_PORT}
33+
_TEST_IPV6_ENVIRON = {SERVICE_HOST_ENV_NAME: _TEST_IPV6_HOST,
34+
SERVICE_PORT_ENV_NAME: _TEST_PORT}
3135

3236

3337
class InClusterConfigTest(unittest.TestCase):
@@ -48,38 +52,29 @@ def _create_file_with_temp_content(self, content=""):
4852

4953
def get_test_loader(
5054
self,
51-
host_env_name=_SERVICE_HOST_ENV_NAME,
52-
port_env_name=_SERVICE_PORT_ENV_NAME,
5355
token_filename=None,
5456
cert_filename=None,
5557
environ=_TEST_ENVIRON):
5658
if not token_filename:
5759
token_filename = self._create_file_with_temp_content(_TEST_TOKEN)
5860
if not cert_filename:
59-
cert_filename = self._create_file_with_temp_content()
61+
cert_filename = self._create_file_with_temp_content(_TEST_CERT)
6062
return InClusterConfigLoader(
61-
host_env_name=host_env_name,
62-
port_env_name=port_env_name,
6363
token_filename=token_filename,
6464
cert_filename=cert_filename,
6565
environ=environ)
6666

67+
def test_join_host_port(self):
68+
self.assertEqual(_TEST_HOST_PORT,
69+
_join_host_port(_TEST_HOST, _TEST_PORT))
70+
self.assertEqual(_TEST_IPV6_HOST_PORT,
71+
_join_host_port(_TEST_IPV6_HOST, _TEST_PORT))
72+
6773
def test_load_config(self):
68-
cert_filename = self._create_file_with_temp_content()
74+
cert_filename = self._create_file_with_temp_content(_TEST_CERT)
6975
loader = self.get_test_loader(cert_filename=cert_filename)
7076
loader._load_config()
71-
self.assertEqual("https://%s:%s" % (_TEST_HOST, _TEST_PORT),
72-
loader.host)
73-
self.assertEqual(cert_filename, loader.ssl_ca_cert)
74-
self.assertEqual(_TEST_TOKEN, loader.token)
75-
76-
def test_load_config_with_bracketed_hostname(self):
77-
cert_filename = self._create_file_with_temp_content()
78-
loader = self.get_test_loader(cert_filename=cert_filename,
79-
environ=_TEST_IPV6_ENVIRON)
80-
loader._load_config()
81-
self.assertEqual("https://[%s]:%s" % (_TEST_IPV6_HOST, _TEST_PORT),
82-
loader.host)
77+
self.assertEqual("https://" + _TEST_HOST_PORT, loader.host)
8378
self.assertEqual(cert_filename, loader.ssl_ca_cert)
8479
self.assertEqual(_TEST_TOKEN, loader.token)
8580

@@ -92,21 +87,45 @@ def _should_fail_load(self, config_loader, reason):
9287
pass
9388

9489
def test_no_port(self):
95-
loader = self.get_test_loader(port_env_name="not_exists_port")
90+
loader = self.get_test_loader(
91+
environ={SERVICE_HOST_ENV_NAME: _TEST_HOST})
9692
self._should_fail_load(loader, "no port specified")
9793

94+
def test_empty_port(self):
95+
loader = self.get_test_loader(
96+
environ={SERVICE_HOST_ENV_NAME: _TEST_HOST,
97+
SERVICE_PORT_ENV_NAME: ""})
98+
self._should_fail_load(loader, "empty port specified")
99+
98100
def test_no_host(self):
99-
loader = self.get_test_loader(host_env_name="not_exists_host")
101+
loader = self.get_test_loader(
102+
environ={SERVICE_PORT_ENV_NAME: _TEST_PORT})
100103
self._should_fail_load(loader, "no host specified")
101104

105+
def test_empty_host(self):
106+
loader = self.get_test_loader(
107+
environ={SERVICE_HOST_ENV_NAME: "",
108+
SERVICE_PORT_ENV_NAME: _TEST_PORT})
109+
self._should_fail_load(loader, "empty host specified")
110+
102111
def test_no_cert_file(self):
103112
loader = self.get_test_loader(cert_filename="not_exists_file_1123")
104113
self._should_fail_load(loader, "cert file does not exists")
105114

115+
def test_empty_cert_file(self):
116+
loader = self.get_test_loader(
117+
cert_filename=self._create_file_with_temp_content())
118+
self._should_fail_load(loader, "empty cert file provided")
119+
106120
def test_no_token_file(self):
107121
loader = self.get_test_loader(token_filename="not_exists_file_1123")
108122
self._should_fail_load(loader, "token file does not exists")
109123

124+
def test_empty_token_file(self):
125+
loader = self.get_test_loader(
126+
token_filename=self._create_file_with_temp_content())
127+
self._should_fail_load(loader, "empty token file provided")
128+
110129

111130
if __name__ == '__main__':
112131
unittest.main()

0 commit comments

Comments
 (0)