DND-1415: native in-pod HTTPS/TLS support (GH #14) - #26
Merged
Conversation
Add config.tls to terminate HTTPS in the pod via S3Proxy's secure-endpoint, using a PKCS12 (or JKS) keystore + password supplied by an existing Secret (recommended; also the cert-manager path) or inline. When enabled, the proxy serves HTTPS only on service.targetPort (port named https); tcpSocket probes are unchanged (they do not perform a TLS handshake). The keystore password is kept out of the ConfigMap: it is merged from the Secret by the config-merge initContainer (inline via secret-common.properties, existingSecret via a mounted file). - values/configmap/secret/deployment/service: config.tls block, secure-endpoint + keystore-path, keystore mount at /tls, password via secret-merge, https port. - CI: test-values/tls.yaml + tls-existing-secret.yaml (lint-render) and a kind functional TLS leg that builds a self-signed keystore Secret and round-trips over HTTPS. smoke-test.sh gains an optional SCHEME arg. - README / override example: TLS / HTTPS section. Chart 0.2.0 -> 0.3.0. Verified: helm lint, kubeconform -strict, helm-polish, shellcheck, actionlint, non-TLS render unchanged, and a kind end-to-end HTTPS round-trip.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Replace the duplicated ternary at the top of deployment.yaml and service.yaml with a shared s3proxy.portName helper in _helpers.tpl. Render is byte-identical for both TLS-on and TLS-off.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- Convert .cursorrules to CLAUDE.md and strengthen the README rule: never hand-edit or regenerate README.md in a PR. Edit README.md.gotmpl + values.yaml; the release workflow renders and commits README.md on merge, and preview-readme previews the diff on the PR. - Revert the generated README.md in this PR back to base (let the release action render it). - Indent the ternary in the s3proxy.portName helper body (cosmetic; render identical for TLS on and off).
📝 README.md PreviewThe following changes to Click to expand diffdiff --git a/README.md b/README.md
index 6d94a16..572a68f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# s3proxy
-  
+  
A Helm chart for deploying S3Proxy - Access other storage backends via the S3 API
@@ -583,6 +583,48 @@ The following section lists the configurable parameters of the s3proxy chart and
<td><code>bool</code></td>
<td><code>false</code></td>
</tr>
+ <tr>
+ <td><code>config.tls.enabled</code></td>
+ <td>Enable native in-pod HTTPS (S3Proxy <code>secure-endpoint</code>). When enabled, S3Proxy serves HTTPS only on <code>service.targetPort</code> (the plaintext endpoint is not bound), so TLS is terminated in the pod rather than at the ingress. Requires a PKCS12 (or JKS) keystore and its password. <code>tcpSocket</code> health probes are unaffected (they do not perform a TLS handshake).</td>
+ <td><code>bool</code></td>
+ <td><code>false</code></td>
+ </tr>
+ <tr>
+ <td><code>config.tls.keystore.existingSecret</code></td>
+ <td>Name of an existing Secret holding the keystore file (binary PKCS12/JKS). Takes precedence over <code>value</code>. Use this for a customer-provided keystore or a cert-manager-issued one (<code>Certificate.spec.keystores.pkcs12</code>).</td>
+ <td><code>string</code></td>
+ <td><code>""</code></td>
+ </tr>
+ <tr>
+ <td><code>config.tls.keystore.secretKey</code></td>
+ <td>Key within <code>keystore.existingSecret</code> (or, when <code>value</code> is used, within the chart's own Secret) that holds the keystore file</td>
+ <td><code>string</code></td>
+ <td><code>"keystore.p12"</code></td>
+ </tr>
+ <tr>
+ <td><code>config.tls.keystore.value</code></td>
+ <td>Inline base64-encoded keystore, stored in the chart's own Secret and mounted as a file. Used only when <code>keystore.existingSecret</code> is empty. Convenient for testing; prefer <code>existingSecret</code> in production.</td>
+ <td><code>string</code></td>
+ <td><code>""</code></td>
+ </tr>
+ <tr>
+ <td><code>config.tls.keystorePassword.existingSecret</code></td>
+ <td>Name of an existing Secret holding the keystore password. Takes precedence over <code>value</code>.</td>
+ <td><code>string</code></td>
+ <td><code>""</code></td>
+ </tr>
+ <tr>
+ <td><code>config.tls.keystorePassword.secretKey</code></td>
+ <td>Key within <code>keystorePassword.existingSecret</code> that holds the keystore password</td>
+ <td><code>string</code></td>
+ <td><code>"keystore-password"</code></td>
+ </tr>
+ <tr>
+ <td><code>config.tls.keystorePassword.value</code></td>
+ <td>Inline keystore password, stored in the chart's own Secret and merged into the backend properties by the secret-merge initContainer (kept out of the ConfigMap). Used only when <code>keystorePassword.existingSecret</code> is empty.</td>
+ <td><code>string</code></td>
+ <td><code>""</code></td>
+ </tr>
<tr>
<td><code>config.virtualHost</code></td>
<td>Virtual Host configuration</td>
@@ -958,6 +1000,76 @@ aws --endpoint-url http://localhost:8080 s3 cp test.txt s3://test-bucket/
aws --endpoint-url http://localhost:8080 s3 ls s3://test-bucket/
```
+## TLS / HTTPS (native, in-pod)
+
+By default S3Proxy binds plain HTTP and TLS is expected to be terminated at the
+ingress. Set `config.tls.enabled=true` to have **S3Proxy itself terminate HTTPS in
+the pod** (S3Proxy's `secure-endpoint`). When enabled:
+
+- S3Proxy serves **HTTPS only** on `service.targetPort` (the plaintext endpoint is
+ not bound). The container/Service port is named `https`.
+- The health probes are `tcpSocket`, which only check the TCP accept (no TLS
+ handshake), so they keep working unchanged against the TLS port.
+- A **PKCS12** keystore is expected (Jetty's default keystore type; JKS also works
+ if supplied). S3Proxy exposes only the keystore path and password, so the chart
+ does not set a keystore type.
+- The keystore **password is never written to the ConfigMap**; it is merged into
+ the backend properties from the Secret by the config-merge initContainer.
+
+### Option A: existing Secret (recommended; also the cert-manager path)
+
+Reference a Secret that already holds the keystore file and the password. This is
+also how a cert-manager `Certificate` with `spec.keystores.pkcs12` delivers a
+keystore (point `keystore.existingSecret` at that Secret, and
+`keystorePassword.existingSecret` at the password Secret it references):
+
+```yaml
+config:
+ tls:
+ enabled: true
+ keystore:
+ existingSecret: my-tls # holds the PKCS12 archive
+ secretKey: keystore.p12
+ keystorePassword:
+ existingSecret: my-tls # holds the password (may be the same Secret)
+ secretKey: keystore-password
+```
+
+### Option B: inline keystore + password
+
+Provide the base64-encoded keystore and the password inline; both are stored in the
+chart's own Secret. Convenient for testing; prefer Option A in production.
+
+```yaml
+config:
+ tls:
+ enabled: true
+ keystore:
+ value: "<base64-encoded PKCS12 keystore>"
+ keystorePassword:
+ value: "changeit"
+```
+
+Create a PKCS12 keystore, for example:
+
+```bash
+# From an existing cert + key:
+openssl pkcs12 -export -inkey tls.key -in tls.crt \
+ -out keystore.p12 -passout pass:changeit
+# Inline value:
+base64 -w0 keystore.p12
+# Or as an existing Secret (Option A):
+kubectl create secret generic my-tls \
+ --from-file=keystore.p12=keystore.p12 \
+ --from-literal=keystore-password=changeit
+```
+
+Testing over HTTPS (the CI keystore above is self-signed, so skip verification):
+
+```bash
+aws --endpoint-url https://localhost:9000 --no-verify-ssl s3 ls
+```
+
## CORS Configuration
To enable CORS support:
|
📊 Helm Render Diff SummaryChart
|
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
GH #14 asks for native HTTPS: configure a PKCS12 keystore path + password, ideally via a Secret. Today the chart binds plain HTTP only (
s3proxy.endpoint=http://...), so TLS can only be terminated at the ingress. This adds in-pod TLS termination via S3Proxy'ssecure-endpoint.What
New
config.tlsblock. Whenconfig.tls.enabled=true:service.targetPortvias3proxy.secure-endpoint(the plaintext endpoint is not bound). The container/Service port is namedhttps.tcpSocketliveness/readiness probes are unchanged: they only check the TCP accept, so they work against a TLS port without a handshake.Keystore + password sources (both supported):
keystore.existingSecret/secretKeyandkeystorePassword.existingSecret/secretKey. Point these at the Secret a cert-managerCertificate(spec.keystores.pkcs12) produces.keystore.value(base64 PKCS12, stored in the chart's Secretdata:) andkeystorePassword.value(stored insecret-common.properties). Convenient for testing.PKCS12 is the expected format (Jetty's default keystore type); S3Proxy exposes only path + password, so no keystore type is set. JKS also works if supplied.
Verified against S3Proxy source (
s3proxy-3.3.0)s3proxy.secure-endpoint/s3proxy.keystore-path/s3proxy.keystore-password(S3ProxyConstants.java).S3Proxy.java).SslContextFactory.Server.Testing
CI coverage added:
test-values/tls.yaml(inline) +test-values/tls-existing-secret.yamlin the lint-render matrix (both code paths).tlsfunctional leg infunctional-test.yaml(self-signed keystore Secret, HTTPS round-trip).Notes
0.2.0to0.3.0(minor; new feature).httpport name. The non-TLS render is unchanged apart from the chart version label and the recomputed checksums.