Skip to content

Commit

Permalink
Add TLS config for server routes
Browse files Browse the repository at this point in the history
Adds the ability to mount a keystore.jks file for setting up routes that
host an HTTP server over TLS.
  • Loading branch information
Josh Hunziker committed Jun 4, 2024
1 parent c6dbf6d commit a23f5f5
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 39 deletions.
92 changes: 61 additions & 31 deletions operator/webhook/introute/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

TRUSTSTORE_PATH = "/etc/cabundle"

KEYSTORE_PATH = "/etc/keystore"

class VolumeConfig:
"""
Expand All @@ -21,7 +22,8 @@ class VolumeConfig:
"""

_route_vol_name = "integration-route-config"
_tls_vol_name = "truststore"
_tls_truststore_name = "truststore"
_tls_keystore_name = "keystore"

def __init__(self, parent_spec) -> None:
self._route_config = parent_spec["routeConfigMap"]
Expand Down Expand Up @@ -62,20 +64,39 @@ def get_volumes(self) -> List[Mapping]:
)

if self._tls_config:
volumes.append(
{
"name": self._tls_vol_name,
"configMap": {
"name": self._tls_config["configMapName"],
"items": [
{
"key": self._tls_config["key"],
"path": self._tls_config["key"],
}
],
},
}
)
client_config = self._tls_config['clientConfig']
if client_config:
volumes.append(
{
"name": self._tls_truststore_name,
"configMap": {
"name": client_config["configMapName"],
"items": [
{
"key": client_config["key"],
"path": client_config["key"],
}
],
},
}
)

server_config = self._tls_config['serverConfig']
if server_config:
volumes.append(
{
"name": self._tls_keystore_name,
"secret": {
"secretName": server_config["secretName"],
"items": [
{
"key": server_config["key"],
"path": server_config["key"],
}
],
},
}
)

return volumes

Expand Down Expand Up @@ -111,15 +132,23 @@ def get_mounts(self) -> List[Mapping]:
"mountPath": cm_spec["mountPath"],
}
)

if self._tls_config:
volume_mounts.append(
{
"name": self._tls_vol_name,
"readOnly": True,
"mountPath": TRUSTSTORE_PATH,
}
)
if self._tls_config['clientConfig']:
volume_mounts.append(
{
"name": self._tls_truststore_name,
"readOnly": True,
"mountPath": TRUSTSTORE_PATH,
}
)
if self._tls_config['serverConfig']:
volume_mounts.append(
{
"name": self._tls_keystore_name,
"readOnly": True,
"mountPath": KEYSTORE_PATH,
}
)

return volume_mounts

Expand Down Expand Up @@ -168,14 +197,15 @@ def _get_java_jdk_options(parent) -> Optional[Mapping[str, str]]:

if not tls_config:
return None

tls_type = tls_config['type']
assert tls_type in ["jks", "pkcs12"], \
f"({tls_type}) is not a supported TLS type. Supported types: ('jks', 'pkcs12')"

truststore_password = "changeit" if tls_type == "jks" else ""
jdk_options = f"-Djavax.net.ssl.trustStore={str(Path(TRUSTSTORE_PATH, tls_config['key']))} -Djavax.net.ssl.trustStorePassword={truststore_password} -Djavax.net.ssl.trustStoreType={tls_type.upper()}"

if 'clientConfig' in tls_config:
tls_type = tls_config['clientConfig']['type']
assert tls_type in ["jks", "pkcs12"], \
f"({tls_type}) is not a supported TLS type. Supported types: ('jks', 'pkcs12')"

truststore_password = "changeit" if tls_type == "jks" else ""
jdk_options = f"-Djavax.net.ssl.trustStore={str(Path(TRUSTSTORE_PATH, tls_config['clientConfig']['key']))} -Djavax.net.ssl.trustStorePassword={truststore_password} -Djavax.net.ssl.trustStoreType={tls_type.upper()}"
if 'serverConfig' in tls_config:
jdk_options += f" -Djavax.net.ssl.keyStore={str(Path(KEYSTORE_PATH, tls_config['serverConfig']['key']))}"
return {
"name": "JDK_JAVA_OPTIONS",
"value": jdk_options,
Expand Down
12 changes: 9 additions & 3 deletions operator/webhook/test/json/full-iroute-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,15 @@
"testroute-secret"
],
"tls": {
"configMapName": "test-tls-cm",
"key": "test-truststore.p12",
"type": "pkcs12"
"serverConfig": {
"secretName": "test-tls-secret",
"key": "test-keystore.jks"
},
"clientConfig": {
"configMapName": "test-tls-cm",
"key": "test-truststore.p12",
"type": "pkcs12"
}
},
"configMaps": [
{
Expand Down
19 changes: 18 additions & 1 deletion operator/webhook/test/json/full-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
"name": "truststore",
"readOnly": true,
"mountPath": "/etc/cabundle"
},
{
"name": "keystore",
"readOnly": true,
"mountPath": "/etc/keystore"
}
],
"livenessProbe": {
Expand All @@ -92,7 +97,7 @@
},
{
"name": "JDK_JAVA_OPTIONS",
"value": "-Djavax.net.ssl.trustStore=/etc/cabundle/test-truststore.p12 -Djavax.net.ssl.trustStorePassword= -Djavax.net.ssl.trustStoreType=PKCS12"
"value": "-Djavax.net.ssl.trustStore=/etc/cabundle/test-truststore.p12 -Djavax.net.ssl.trustStorePassword= -Djavax.net.ssl.trustStoreType=PKCS12 -Djavax.net.ssl.keyStore=/etc/keystore/test-keystore.jks"
}
]
}
Expand Down Expand Up @@ -139,6 +144,18 @@
}
]
}
},
{
"name": "keystore",
"secret": {
"secretName": "test-tls-secret",
"items": [
{
"key": "test-keystore.jks",
"path": "test-keystore.jks"
}
]
}
}
]
}
Expand Down
22 changes: 18 additions & 4 deletions operator/webhook/test/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def test_spring_app_config_json_missing_props_and_secret_sources(full_route):


def test_jdk_options_pkcs12_type(full_route):
del full_route["spec"]["tls"]["serverConfig"]
options = _get_java_jdk_options(full_route)

assert options["name"] == JDK_OPTIONS_ENV_NAME
Expand All @@ -85,19 +86,32 @@ def test_jdk_options_pkcs12_type(full_route):

def test_jdk_options_jks_type(full_route):
tls_config = full_route["spec"]["tls"]
tls_config["type"] = "jks"
tls_config["key"] = "test-truststore.jks"
tls_config["clientConfig"]["type"] = "jks"
tls_config["clientConfig"]["key"] = "test-truststore.jks"
tls_config["serverConfig"]["key"] = "test-keystore.jks"

options = _get_java_jdk_options(full_route)

assert options["name"] == JDK_OPTIONS_ENV_NAME

expected_options = "-Djavax.net.ssl.trustStore=/etc/cabundle/test-truststore.jks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=JKS"
expected_options = "-Djavax.net.ssl.trustStore=/etc/cabundle/test-truststore.jks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=JKS -Djavax.net.ssl.keyStore=/etc/keystore/test-keystore.jks"
assert options["value"] == expected_options

def test_jdk_options_jks_type_no_server(full_route):
tls_config = full_route["spec"]["tls"]
tls_config["clientConfig"]["type"] = "jks"
tls_config["clientConfig"]["key"] = "test-truststore.jks"

del full_route["spec"]["tls"]["serverConfig"]
options = _get_java_jdk_options(full_route)

assert options["name"] == JDK_OPTIONS_ENV_NAME

expected_options = "-Djavax.net.ssl.trustStore=/etc/cabundle/test-truststore.jks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=JKS"
assert options["value"] == expected_options

def test_jdk_options_unknown_type(full_route):
tls_config = full_route["spec"]["tls"]
tls_config = full_route["spec"]["tls"]["clientConfig"]
tls_config["type"] = "pem"

with pytest.raises(AssertionError):
Expand Down

0 comments on commit a23f5f5

Please sign in to comment.