8000 Implement conversion of PEM CA bundle to JKS TrustStore · localstack/localstack@048f622 · GitHub
[go: up one dir, main page]

Skip to content

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

8000
Appearance settings

Commit 048f622

Browse files
Implement conversion of PEM CA bundle to JKS TrustStore
1 parent 070dbc2 commit 048f622

File tree

2 files changed

+107
-19
lines changed

2 files changed

+107
-19
lines changed

localstack-core/localstack/services/opensearch/packages.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
from localstack.services.opensearch import versions
2222
from localstack.utils.archives import download_and_extract_with_retry
2323
from localstack.utils.files import chmod_r, load_file, mkdir, rm_rf, save_file
24-
from localstack.utils.java import java_proxy_cli_args
24+
from localstack.utils.java import (
25+
java_system_properties_proxy,
26+
java_system_properties_ssl,
27+
system_properties_to_cli_args,
28+
)
2529
from localstack.utils.run import run
2630
from localstack.utils.ssl import create_ssl_cert, install_predefined_cert_if_available
2731
from localstack.utils.sync import SynchronizedDefaultDict, retry
@@ -66,7 +70,6 @@ def _install(self, target: InstallTarget):
6670
tmp_archive = os.path.join(
6771
config.dirs.cache, f"localstack.{os.path.basename(opensearch_url)}"
6872
)
69-
print(f"DEBUG: installing opensearch to path {install_dir_parent}")
7073
download_and_extract_with_retry(opensearch_url, tmp_archive, install_dir_parent)
7174
opensearch_dir = glob.glob(os.path.join(install_dir_parent, "opensearch*"))
7275
if not opensearch_dir:
@@ -86,20 +89,26 @@ def _install(self, target: InstallTarget):
8689
# install other default plugins for opensearch 1.1+
8790
# https://forum.opensearch.org/t/ingest-attachment-cannot-be-installed/6494/12
8891
if parsed_version >= "1.1.0":
92+
# Determine network configuration to use for plugin downloads
93+
sys_props = {
94+
**java_system_properties_proxy(),
95+
**java_system_properties_ssl(
96+
os.path.join(install_dir, "jdk", "bin", "keytool"),
97+
{"JAVA_HOME": os.path.join(install_dir, "jdk")},
98+
),
99+
}
100+
java_opts = system_properties_to_cli_args(sys_props)
101+
89102
for plugin in OPENSEARCH_PLUGIN_LIST:
90103
plugin_binary = os.path.join(install_dir, "bin", "opensearch-plugin")
91104
plugin_dir = os.path.join(install_dir, "plugins", plugin)
92105
if not os.path.exists(plugin_dir):
93106
LOG.info("Installing OpenSearch plugin %s", plugin)
94107

95108
def try_install():
96-
opts = java_proxy_cli_args() + [
97-
"-Djavax.net.ssl.trustStore=/home/viren/mitmproxycacert.jks",
98-
"-Djavax.net.ssl.keyStorePassword=localstack",
99-
]
100109
output = run(
101110
[plugin_binary, "install", "-b", plugin],
102-
env_vars={"CLI_JAVA_OPTS": " ".join(opts)},
111+
env_vars={"OPENSEARCH_JAVA_OPTS": " ".join(java_opts)},
103112
)
104113
LOG.debug("Plugin installation output: %s", output)
105114

@@ -249,6 +258,16 @@ def _install(self, target: InstallTarget):
249258
mkdir(dir_path)
250259
chmod_r(dir_path, 0o777)
251260

261+
# Determine network configuration to use for plugin downloads
262+
sys_props = {
263+
**java_system_properties_proxy(),
264+
**java_system_properties_ssl(
265+
os.path.join(install_dir, "jdk", "bin", "keytool"),
266+
{"JAVA_HOME": os.path.join(install_dir, "jdk")},
267+
),
268+
}
269+
java_opts = system_properties_to_cli_args(sys_props)
270+
252271
# install default plugins
253272
for plugin in ELASTICSEARCH_PLUGIN_LIST:
254273
plugin_binary = os.path.join(install_dir, "bin", "elasticsearch-plugin")
@@ -257,13 +276,9 @@ def _install(self, target: InstallTarget):
257276
LOG.info("Installing Elasticsearch plugin %s", plugin)
258277

259278
def try_install():
260-
opts = java_proxy_cli_args() + [
261-
"-Djavax.net.ssl.trustStore=/home/viren/mitmproxycacert.jks",
262-
"-Djavax.net.ssl.keyStorePassword=localstack",
263-
]
264279
output = run(
265280
[plugin_binary, "install", "-b", plugin],
266-
env_vars={"CLI_JAVA_OPTS": " ".join(opts)},
281+
env_vars={"ES_JAVA_OPTS": " ".join(java_opts)},
267282
)
268283
LOG.debug("Plugin installation output: %s", output)
269284

localstack-core/localstack/utils/java.py

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
"""
2-
Utilities related to Java runtime environments.
2+
Utilities related to Java runtime.
33
"""
44

5+
import logging
6+
from os import environ
57
from urllib.parse import urlparse
68

79
from localstack.config import OUTBOUND_HTTP_PROXY, OUTBOUND_HTTPS_PROXY
10+
from localstack.utils.files import new_tmp_file, rm_rf
11+
from localstack.utils.run import run
812

13+
LOG = logging.getLogger(__name__)
914

10-
def java_proxy_system_properties() -> list[str]:
15+
16+
#
17+
# Network
18+
#
19+
20+
21+
def java_system_properties_proxy() -> dict[str, str]:
1122
"""
1223
Returns Java system properties for network proxy settings as per LocalStack configuration.
1324
@@ -33,15 +44,77 @@ def java_proxy_system_properties() -> list[str]:
3344
return props
3445

3546

36-
def java_proxy_cli_args() -> list[str]:
47+
#
48+
# SSL
49+
#
50+
51+
52+
def build_trust_store(
53+
keytool_path: str, pem_bundle_path: str, env_vars: dict[str, str], store_passwd: str
54+
) -> str:
3755
"""
38-
Returns Java CLI arguments for network proxy settings as per LocalStack configuration.
56+
Build a TrustStore in JKS format from a PEM certificate bundle.
57+
58+
:param keytool_path: path to the `keytool` binary.
59+
:param pem_bundle_path: path to the PEM bundle.
60+
:param env_vars: environment variables passed during `keytool` execution. This should contain JAVA_HOME and other relevant variables.
61+
:param store_passwd: store password to use.
62+
:return: path to the truststore file.
3963
"""
40-
args = []
64+
store_path = new_tmp_file(suffix=".jks")
65+
rm_rf(store_path)
66+
67+
LOG.debug("Building JKS trust store for %s at %s", pem_bundle_path, store_path)
68+
cmd = f"{keytool_path} -importcert -trustcacerts -alias localstack -file {pem_bundle_path} -keystore {store_path} -storepass {store_passwd} -noprompt"
69+
run(cmd, env_vars=env_vars)
70+
71+
return store_path
72+
73+
74+
def java_system_properties_ssl(keytool_path: str, env_vars: dict[str, str]) -> dict[str, str]:
75+
"""
76+
Returns Java system properties for SSL settings as per LocalStack configuration.
77+
78+
See https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#CustomizingStores
79+
"""
80+
props = {}
81+
82+
if ca_bundle := environ.get("REQUESTS_CA_BUNDLE"):
83+
store_passwd = "localstack"
84+
store_path = build_trust_store(keytool_path, ca_bundle, env_vars, store_passwd)
85+
props["javax.net.ssl.trustStore"] = store_path
86+
props["javax.net.ssl.trustStorePassword"] = store_passwd
87+
props["javax.net.ssl.trustStoreType"] = "jks"
88+
89+
return props
90+
91+
92+
#
93+
# Other
94+
#
95+
4196

42-
props = java_proxy_system_properties()
97+
def system_properties_to_cli_args(properties: dict[str, str]) -> list[str]:
98+
"""
99+
Convert a dict of Java system properties to a list of CLI arguments.
100+
101+
e.g.::
102+
103+
{
104+
'java.sys.foo': 'bar',
105+
'java.sys.lorem': 'ipsum'
106+
}
107+
108+
returns::
109+
110+
[
111+
'-Djava.sys.foo=bar',
112+
'-Djava.sys.lorem=ipsum',
113+
]
114+
"""
115+
args = []
43116

44-
for arg_name, arg_value in props.items():
117+
for arg_name, arg_value in properties.items():
45118
args.append(f"-D{arg_name}={arg_value}")
46119

47120
return args

0 commit comments

Comments
 (0)
0